ColdFusion 9's Implicit Getters And Setters Are Hard Coded
Posted June 3, 2010 at 8:46 AM by Ben Nadel
The other day, I was day dreaming about the awesomeness that is ColdFusion 9 when I had a thought about its new implicit getters and setters. I know that ColdFusion 9 added the function, getFunctionCalledName(); so, I wondered if the implicit getter and setter methods were actually shared functions that operated based on their run-time handles. To test this, I set up a very simple ColdFusion component that had two properties:
- hint="I am a test component with implicit getters.">
- <!--- Define properties. --->
- <!--- This will have both accessors. --->
- <!--- This will have only a setter. --->
- Set some default values using the implicit setters
- defined by the above CFProperty tags.
- <cfset this.setName( "Tricia" ) />
- <cfset this.setPetName( "Cutie" ) />
Notice that both properties of this Girl - name and petName - have implicit setter methods; but, only the name property has a getter. This will cause the petName property of this object to be unreadable. So the question is, if I copy the getName() function reference into the "getPetName" component key, will I be able to access the underlying property?
- <!--- Create an instance of the girl object. --->
- <cfset girl = new Girl() />
- Copy the getName() reference into the getPetName
- key - remember, there was no implicit getter for
- pet name.
- <cfset girl.getPetName = girl.getName />
- <!--- Output the various values. --->
- Name: #girl.getName()#<br />
- <br />
- Pet Name: #girl.getPetName()#
As you can see, all we are doing is copying the getName() reference to another key within the same component. If the accessors work off of their run-time names, then this would provide access to the petName property which was not given an implicit getter by default. When we run this code, however, we get the following page output:
Pet Name: Tricia
As you can see, copying the implicit getter to another run-time variable did not change its underlying execution. As such, we can be confident that the code behind ColdFusion 9's implicit (or rather synthesized) accessors is hard-coded and specific to the originating property.
Great stuff. I had a hard time with something similar in CF8. I was writing my own getters and setters, but had some problems figuring out a proper variable scope, because cfproperty had some issues with exactly this type of code.
This is exactly what I anticipated would happen. I assume that the function pointer is overwritten and now they both point to the same method.
If this would have worked, it would have been a huge security gap in ColdFusion.
It would have been a security gap; however, ColdFusion is so dynamic, that you can always plug in your own functions to existing CFCs at runtime to circumvent access rights.
So, what must be happening is that when the code is parsed, ColdFusion must actually read the CFProperty tags (which must be first in the file) and then compile individual getters / setter functions for each appropriate property.
I guess it makes sense; I just figured that this is the kind of thing that getFunctionCalledName() would be used for - otherwise, I have no idea for what core reason they added that method.
Ben, you're a nut -- always digging deep into parts of CF that nobody in their right mind should ever use.
And that's why I *love* following your blog. Keep up the obsessively thorough work!
Thanks my man. I just really like to know how this stuff works - to see how it can be leveraged for fun and profit (to borrow a phrase from Dan Wilson).
Does anyone know if implicit getter and setter function are created as public or remote functions; can it be overridden?
As far as I know, they are created as public; defaulting them to Remote would probably pose a security risk. Also, you can override them simply by defining your own. When ColdFusion builds the CFC, it will check to see if you have defined your own getter/setter methods before trying to synthesize them.
What I am wondering is why are they faster than the regular explicit function or at least they seem to be in the few test we've done.
@JF, Since the classes they belong to are generated only once, I assume it will be directly compiled into a java class. And then it would make sense that it's faster in execution, because the interpreter for CFML is just skipped.
But then again, I'm just making an educated guess here. Maybe someone with more thorough knowledge of CF's inner workings can prove me wrong...
Hmm, interesting question. I had assumed that a synthesized getter/setter actually got compiled down into the same code as any manually coded UDF; but, like @Steven, that's just a guess.
What would be an interesting experiment was to see if the method could be removed from the CFC instance with a structDelete( cfc, "getterName" ). If that works, I would assume that the method is being treated like any UDF, but I don't think I've tried this.... and to be fair, it really wouldn't prove anything one way or the other :D
At the end of the day, synthesized getters and setters are useful until they are not. I wouldn't worry too much about the actual performance.
.... that said, Elliott Sprehn always preaches that you should *believe in the language*. That it will be able to do things more efficiently than anything you could do manually. So, in that mindset, it would make sense that the synthesized methods are *at least* as fast, if not faster than manually coded methods.
Out of curiosity I tried deleting the implicit method with StructDelete (it worked). Tried to access it after the delete and it was still available and returned me the default value.
Did that as well :
and here is the result
Seems like it is instantiated directly in the CF runtime (? I think)..
Very interesting! Now my curiosity is piqued. I'll have to do some exploration. Thanks for doing some digging.
I did some more in-depth exploration of the behavior of ColdFusion 9's implicit getters and setters.
They seem to be mostly like standard User Defined Functions. The only real difference I saw was that the internal property reference could not be overridden... which has me very curious.