Blog

27
December 2013

Gavin Pickin

To Init or Not to Init - CFC Component Init Function

CFML Language, Techie Gotchas

In a comment on my Unit Testing on TDDSean Corfield mentioned that I did not need to explicitly call .init() on my object creation when using the new syntax... because the new syntax called it implicitly for you, if it exists, and fails silently if it does not exist. I know I had heard this somewhere, but I knew there was a reason why I was used to putting .init() on all object creation calls, but I had forgotten. Getting older, that time of the year, not sure what the excuse is, so I decided I'd do a little testing and try and jog my memory.

For some reason, I think the core of this issue came from our legacy code, and a lot of it still running on some ColdFusion 8 servers. We had been meaning to upgrade it to ColdFusion 9, but then ColdFusion 10 came out, and then we decided to migrate servers, and now 11 is coming out soon, all out new development is for newer versions, but a lot of our old code, we maintain, on the old boxes. So, the first thing I wondered was, when did this "new" syntax come out... and has it always done the initialization for you?

I have been touching up on my ColdFusion Object Oriented Programming lately, so while I waited to buy Matt Gifford's book Object Oriented Programming for ColdFusion from Packt Publishing (E Book on sale for only $5 right now), I have read over Adrian Moreno's OOP Blog entries at http://www.iknowkungfoo.com/ and Kevan Stannard's Site http://objectorientedcoldfusion.org/. I like to read a lot of different material, and they both have some solid beginner information, but the one thing I didn't notice was, they are a little dated, and neither one mentioned the "new" syntax. All of the examples all explicitly called the init() function, as at that time, it was a convention to call the init() method, but CFML had not actually added it to the language, when those examples were written, in ColdFusion 8's time.

Doing a little research, Dan Skaggs pointed it out on his Blog back in April of 2010, and some of the comments said they didn't notice this change, one of them, even into ColdFusion 10. Ben Nadel had a lot of posts in July and August 2010 on new vs entityNew and CreateObject, using dynamic paths with the new operator, and how to use new with cfimport even with tags  I found some Railo notes, most importantly was a JIRA ticket in May 2010 when Micha added a ticket and completed the ticket (all in a day by the looks of it) and supported multiple syntax param options, released in Railo 3.1. I am not sure if there was script support before, or just some param options or not. 

<cfset test2=new TestNewOperator1(1)>
<cfset test1=NEW TestNewOperator1()>
<cfset test1=new TestNewOperator1(1,2,3)>
<cfset test1=new TestNewOperator1(a:1)>
<cfset test1=new TestNewOperator1(a=1)>

 

So, thanks to my research assistant Google, it looks like April / May of 2010... the cfml community received the new syntax, whether we all knew about it or not.
I found this article from Adobe, to confirm this... and something I didn't know.

ColdFusion looks for a method called initmethod() first, and runs that if it is found. If not, then it looks for a method called init() and then runs that if it is found, and then if neither are found, it just instantiates the component. Now, I tested this out in CF 9.0.2... and this is incorrect... initmethod does not get called... init is called if they both exist, and if init does not exist, initmethod is not called either. 

Another interesting tidbit, the new operator returns the value returned by init or initmethod, if void, it returns the instance of the CFC... so you dont have to return the THIS pointer. If you return something else, it will not behave as expected... since new will init it, but not necessarily always return the object, as best practices state you should always do. If you had your code setup to run the init as a separate call, and returned some value previously, like a boolean, created, etc, when using the new syntax, you might accidentally store the boolean by mistake, since the init is called implicitly now. I tested that, and it works as expected, although, if you follow best practices and return this, it would not be an issue.

Although, you do not need to return this if using the new syntax... but that isn't intuitive, or obvious, even Ben Nadel mentioned (granted it is an old blog post) that you must return the THIS pointer if you want to return the object instance... but you can return nothing, and the cfml engine will automatically return the pointer for you.

I tested Railo's compatibility, and it matches CF9's results, not the documented initmethod stuff. 
Then, I decided to find out, when did they remove the initmethod stuff? I did some more reading, and I found out they never removed it, it was just not documented in a way that I could understand it. And even when I did understand it, the documentation was still wrong. In Ben Nadels blog entry on cfimport and new works with tags too , he spells out the actual way it works.

  1. ColdFusion looks for the InitMethod attribute on the target CFC's CFComponent tag. If the attribute exists, it executes the method named within that attribute (CAUTION: If the name is not accurate, ColdFusion throws an error).
  2. If the InitMethod attribute does not exist, ColdFusion looks for a function with the name "Init" (which has become the de facto way to name CFC constructors) and executes it.
  3. If neither the InitMethod attribute nor the Init method are found, ColdFusion does not invoke any constructor and simply returns the instantiated CFC. In this case, any arguments to pass in using the new operator are simply ignored.

Adobe's documentation fail to mention initmethod is an "attributes" on the target cfc's component tag. This allows you to specify any tag as the function to initialize. I'm not sure why, but you could have ColdFusion initialize something other than the init, maybe knowing the init was used by legacy code, and the "new" initialization should be something else.

The other issue with their documentation is, they say

If it does not find an initmethod constructor method, it looks for an init constructor method. 
If found, ColdFusion instantiates the component and runs initmethod.

They obviously intended it to say runs the init method / function... not the initmethod method / function.
Note, if your initmethod attributes is misspelled, or set to an invalid function, it will throw an error. I was thinking about how it might be cool to make your init method private, so you could only call the init on new creation using the "new" operator, but the initmethod must point to a valid public, package, or remote method / function.

The short of it is, only CF9+ and I believe it is Railo 3.1+ support the new operator. The operator is pretty flexible, fixed and dynamic paths, it will auto init for you, will return the pointer implicitly (although might be confusing) or return explicitly something other than the THIS pointer (really confusing - I do not recommend this), and work almost identically across the Adobe ColdFusion and Railo, although, Railo does not support the initmethod Attributes in the CFC definition. 

If you use createobject, cfinvoke, or cfobject, you need to initiliaze your components, if you use the "new" operator, you do not.
So do not double init like I did :)

Thanks again Sean Corfield, for pointing it out... and starting me on this journey.

Gavin

My Index.cfm File

My main.cfc (multiple gist revisions for variations)

by Sean Corfield
12/27/2013 07:33:44 PM

Yeah, Adobe have done a very poor job of documenting a lot of the recent language changes.

The reason new returns the result of calling init() - if anything is returned - is to match the behavior of:

var o1 = createObject( "component", "MyThing" ).init();

var o2 = new MyThing;

Here o1 is assigned the result of calling init();

Why does that matter? Some code out there - esp. framework code - returns something other than 'this' from the init() method deliberately, to support proxy objects or object pooling or all sorts of advanced stuff.

by Brad Wood
12/29/2013 07:12:14 PM

Nice write-up. If you are using ORM, entityNew() also calls init automatically.

by paulkd
01/17/2014 09:08:00 AM

I'm not understanding why this has to be returned by the init function (constructors notwithstanding)

<cfset o1 = createObject("component","MyCFC")>

o1 is automatically "this" - no need to set further?

by Gavin
01/17/2014 09:37:16 PM

Hi Paulkd... let me try and answer your question.

I think the reason is more that its a good practice. You always Init all your objects regardless if they need it, so if its an object that needs to be init'ed, you do... and you dont have to remember which ones need to be and dont need to be.

Also, returning this again was a good practice. In the older versions, you would make an object, then call .init() on it after instantiation, because you couldn't in a single call.

You return this, again as good practice, so you know it it returning the object, to be stored. If you returned True from your init method, o1 would have true, and not the method, since you instantiated and init()ed it in one call.

I hope that makes sense.

I guess its "Just because you can, doesn't mean you should" Hopefully one of the "EXPERTS" will chime in and make it clear for us.

Blog Search