Relative CFC Typing and Extending (CFC WTF Part 2)

So I had my big winge about CFCs being able to create other CFCs relatively, but not being able to extend or use return or cfargument types relatively, and how it totally messes up code being truly reusable.

So I’m chatting to Spike about this issue, and he’s looking at my post, and he casually remarks to me: ‘Well, why don’t you try ” rather than ‘.’?  See what happens".

I of course thought to myself, no way is that going to work.. I mean, it’s just silly. It doesn’t even look like a real class name definition.

Well I’ll be damned (and several other loud expletives I echoed at the time), it freakin’ works. And to top it off, it works relatively. Spike came up with the good once again.

So to make myself clear through all this muddle – you are perfectly able to:

  • createObject("component", "comlevelCat")
    – i.e. create Dog.cfc in the folder comlevel folder relative to where you are calling it.
  • <cfargument name="Cat" type="comlevelCat" required="true">
     – i.e The type of the argument is of the Cat.cfc up in the comlevel folder relative to the CFC this is in.
  • <cffunction name="getDog" access="private" returntype="comDog" output="false">
    – i.e The return type of the function is of the Dog.cfc up in the com folder relative to the CFC this is in.
  • <cfcomponent name="Dog" extends="levelextendExtend">
    – i.e. extend the component Extend.cfc in the relative directory of levelextend to the CFC this is in.

This is really big thing as it means that you can relatively go down a folder tree with your inheritence and typing with CFCs. You can’t actually go back up (least I haven’t found a way), but you can go down it.  This means, you have much more ability to write really portable code – as long as you are relatively careful (no pun intended) about how you structure your packages.

for example – if I have a directory structure of:

  • webappa.cfc
  • webapponeb.cfc

i can now make a extend b without going back to root and/or a mapping via:
<cfcomponent name="a" extends="oneb">

As well as do similar things with type and return values on cfargument and cffunction.

Here you can download my relative pathing testbed so you can test it out for yourself, and see all the possibilities.

Quite frankly, this has opened up a whole lot of interesting things in terms of how I want to structure my code, and whether or not a cfmapping is even required when doing CFC development.

No cfmapping – how cool is that?

Leave a Comment

Comments

  • Sean Corfield | April 2, 2005

    Ah, you Windows users…

    Use / instead of so your code works on non-Windows platforms as well.

  • Mark | April 4, 2005

    Sean,

    I did try the code with ‘/’ in mind, however it seems to cause errors of ‘Not of type com/Dog’ if you use it, hence I utilised the ” notation.

    I don’t have a Mac or a Linux box at hand – did you have to change all the ” to ‘/’ to get it to work?

    Mayb ethis technique is OS dependent. Not sure. (That would be bad)

  • Sean Corfield | April 4, 2005

    Yeah, the doesn’t work on Mac or *nix so it seems to be OS dependent. That’s really interesting because everywhere else, CFMX accepts / on Windows… Hmm… that suggests that this relative pathing is working by coincidence and may well break if ever the type lookup mechanism changes in a future release…

  • Mark | April 4, 2005

    Yeah well ;o) we all knew it could break in the future, considering it’s a ‘undocumented feature’.

    That’s a risk that people have to choose to make or not when these types of things are discovered… and that’s a whole ‘nuther conversation.

  • josht | May 20, 2005

    in the comlevelextendextend.cfc you can create the cat object via
    var cat = createObject("component", "WTF2comlevelCat");

    if the files are located http://localhost/wtf2/index.cfm

  • barry.b | June 8, 2005

    >> considering it’s a ‘undocumented feature’.

    yet another example of something useful that’s undocumented.

    so what’s wrong with MACR adding this feature for real? it obviously works? Where’s the (specific for this example) grief? It’s obviously handy and people want it…

    my 2c
    barry.b

  • j buda | September 8, 2006

    How can we make the path go up a directory?

  • Mark | September 9, 2006

    j buda

    You can’t, unfortunatley.

    In all honesty, I’m not a big fan of this technique anymore… but it was very interesting at the time.

  • twiggy | May 8, 2008

    This code only works because CF does not do proper checking on the variable. Put a <cfcom….extends=".myonelevelup.cfc" and it’ll break with a CF specific ( versus java ) error that extends cannot start or end with a dot ("." ).

    If you have debugging on you can get a stack trace of the error..you’ll notice that it comes from coldfusion.runtime.templateproxy.

    Now lets try and break it somemore..

    extends="C:TestBase"

    Notice the C:…this will only work on a windows box…but it’s enough to really break the Java and CF doesn’t handle it and you get a lower level Java error that will tell you what they are doing. Do the stack trace and you’ll notice…

    Stack Trace (click to expand)
    at cfTestDynExt2ecfm1389005333.runPage(C:InetpubwwwrootCompassTestDynExt.cfm:14)

    java.io.IOException: The filename, directory name, or volume label syntax is incorrect
    at java.io.WinNTFileSystem.canonicalize0(Native Method)
    at java.io.Win32FileSystem.canonicalize(Win32FileSystem.java:375)
    at java.io.File.getCanonicalPath(File.java:559)
    at coldfusion.jsp.JRunTagLibraryInfo.lookupTLI(JRunTagLibraryInfo.java:115)
    at coldfusion.jsp.JRunTagLibraryInfo.lookupTLI(JRunTagLibraryInfo.java:104)
    at coldfusion.compiler.NeoTranslationContext.registerTaglib(NeoTranslationContext.java:154)

    The important line is:
    at java.io.File.getCanonicalPath(File.java:559)

    Look at java docs to see how this function works…but this is why the whole "/" format works at all. I think CF is actually replacing dots in the file name with / and then pushing it through…so if no dots…the / works fine…(maybe it’s s…whatever)

    The thing that sucks about this is Adobe could easily make CFC extension be relative…it might require the compiler to open up application.cfc or require some sort of config file, but it is possible.

    The real reason I need this is that we need to have multiple builds of our app on one server. So we end up with /myappv1/my.cfm, /myappv2/my.cfm, and so. So I don’t know the application root until run time.

    I need CF to support something like extends="{root}.com.api.mycfc"

    Lastly, one total hack to make upwords relative pathing is to create a linked directory…u can do it on NT using some resource kit tools…
    Make a directory in your current directly that links to the parent directory. Then you can do extends="myLinkedUpworddir/../../whereamI.cfc

    Definately a hack…but it’ll work. Probably most useful on *nix boxes where linked directories are more common.