Joel asks:
I did have a particular question about the cfc's lecture, specifically about the "init" method which you covered. I am having a difficult time getting my brain around how this works and what relationship it has to other functions in the component.For example, lets' say I have 2 simple methods, getBooks and createBook in my component. How could I use an init method to make this component perform better/more efficiently?
As I understand it from the lecture, I could presumably create an instance of the component with init--say in the App.cfc--which would basically make an empty or generic book in memory. From here, when I need to deal with the the additional methods (get and create), I could invoke the already created instance (from the init). Am I getting this right, or is there something I'm missing?
Let's take a step back as it may make it a bit easier to understand why you would want to use an init method in your CFC. First, imagine that CFC you described above, with two methods. Imagine they both need to work with a datasource. You could imagine both methods than taking an argument for the datasource.
Ok, so far so good. Now imagine they both need to know where a media folder is. Ok, so just add another argument. So now every method in your CFC (which now is just two, but would obviously grow) has 2 additional arguments. This ends up being a lot more work.
As you know, CFCs have their own variables scopes. There is a private Variables scope and a public This scope. If the CFC itself is persisted, then these variables can store information (like a DSN, a media path, etc), that methods can use.
So to make your CFC easier to use, you can add a setDataSource and a setMediaPath method. This would let you set up the values that other methods would use.
Problem solved. But as a pure convenience, it would be nice if you could create your CFC and set up all the values at the same time. That is where the init method comes in. You can think of the init method as simply a way of creating and setting up the CFC for future use. It's like going to the car dealership and asking for a car that has the seat set up correctly and the right radio stations already tuned in. You don't have to do it yourself, it just comes out properly setup.
Does this make sense?
Archived Comments
Ray,
Could you please post some example code for a CFC to show the init method in action?
Alex
Here's some...
http://www.oreillynet.com/p...
By golly, I think I have it.
nice..
And just as a follow up to this, I wanted to touch up on the Init() method when it comes to Java objects which you can create via CreateObject( "java", "...). The Init() method on those objects calls the constructor for a Java object. However, unlike ColdFusion, Java can have several different constructors that take different arguments. Take a look at the Java StringBuffer - it has three constructors:
1. One with no arguments.
2. One with an initial capacity argument.
3. One with the initial content of the buffer.
When you create a StringBuffer and call its Init() method, ColdFusion looks at what arguments you pass in, and then looks at the available Java constructors and picks the one that seems most appropriate (based on your arguments).
So, when it comes to Java, the Init() method calls the Java constructor that is most appropriate. For consistency's sake, people have also adopted the Init() method to the be ColdFusion CFC de facto constructors even though ColdFusion does not enforce this in any way.
I hope that helps more than it hurts :)
To be fair, and I am NOT a Java coder, Ben, what you describe is method overloading. It isn't specific to Init(), but applies to _all_ java methods. Ie, I can build a foo method that takes an int, and one that takes a string. CF doesn't support this.
Ray, that's funny, I never thought about it in terms of standard method overloading (just constructors), but now that you bring it up, it makes a lot of sense. However, I was trying to pull it into the whole Init() discussion and part of why that has become a standard.
It is a shame CF8 doesn't introduce proper constructors. Why they wouldn't make this simple change is beyond me.
init is NOT a constructor, it ist just a method called init no different to any other method.
A constructor would be named the same as the class and called implicity.
[code]
<cfcomponent displayname="shoppingCart">
<cffunction name="shoppingCart" access="public" output="no" returntype="shoppingCart">
<cfargument name="cartID" type="UUID" required="yes">
<cfset variables.cartID = arguments.cartID>
<cfreturn this>
</cffunction>
</cfcomponent>
[/code]
Adobe should seriously consider if it is the long term benefit of CF to be so different and start doing some things the standard way, CF8 has added a couple that I can think of, but still a long way behind
PS: I never understood why <cfcomponent wasn't <cfclass
While I would like to see the idea of a constructor be more formalized, I take issue with you sayign CF is behind.
CF is not OO.
CF should NOT be OO.
And lastly, I pray to God that CF never becomes OO.
If I wanted to do OO, I'd use Java, or .Net. This is one reason why I don't much care about interfaces. Give me a feature like cfajaxproxy over interfaces any day.
When you say it should do things that standard way, what do you mean? OO is the standard? It is _a_ standard. Not _the_ standard.
Ray,
I don't agree at all.
CF is OO, you can create classes, with public and private varibles, create instances, inherit from other classes, define interfaces. It is very OO, just missing some of the bits.
OO is the one and only standard, that's most languages has OO of some sort. It is what they teach at schools what 90%+ of developers use.
If you are not using CF in an OO way, then you are behind the game.
CF8: Is still behind from an OO point of view, ahead in many other areas. I'm just one of those people who want more OO stuff in CF, and as I said being added slowly, but I want it quicker.
We are going to have to agree to disagree on this one. I don't think you will find many people who agree with your 'CF is OO' statement, not do I think you will find people who _want_ CF to be OO.
But lets not turn this into a big long argument as I don't want to get too far off topic. Maybe tomorrow morning I'll start up a new blog entry on this topic. (And lets take a guess as to how high the comment count will get.)
Let's not forget the pseudo-constructor, the loose code in the component that is executed on creation. A couple years ago at a conference when I was beginning to learn how to implement OO in CF specifically, I asked one of the pros what their opinion was on always executing init() in the pseudo-constructor, effectively making init() implicitly called, albeit by manual means from the perspective of writing the CFC, but when consuming the CFC it would seem more OO-ish. He shot that idea down in front of the whole session audience. It always seemed like a good idea to me. But I terminated the practice after getting that feedback.
I don't think he should have shot you down, but one of the reasons not to do this is that one of the benefits of a constructor is the ability to pass in paramaters.
So you can't do that with the method you explained.
I use Init now days, but as it's not a language feature and more of a style and common way of achiving CF's lacking of a proper constructor it's very easy for a newbie to not understand.
Hey Dale, later today I'm going to blog on CF/OO. Check the blog and please correct me if I misquote you.
I was probably the person who "shot down" using init() in the pseudo-constructor - I've always said it's a very bad idea. The problem is that the pseudo-constructor is executed whenever the object is created - and that includes when you browse the CFC auto-generated documentation. It will also interfere with the ability to use ColdSpring since it assumes that it will call init() - the constructor - after it has created the object and resolved the dependencies.
I'm glad to here you don't do it any more Joshua!
Dale, CF does not "lack a proper constructor". Constructors are just methods. In some languages they have the same name as the class, in other languages they do not. Check out Smalltalk, for example.
Remember that when CF deals with Java objects, it uses this idiom:
createObject("java","somepackage.SomeClass").init(args)
that's exactly the same way you deal with CF objects.
Remember that New Atlanta added "proper constructors" to BlueDragon at one point and then they removed them again - presumably because their customers didn't actually like the way it worked or it was just not idiomatic.
Sean,
To me a constructor is called when you create the object without you having to remember to do something.
I use the init method, it does the job and not having implicit constructors is no great loss but I would have prefered it over Interfaces.
It is also the number one feature of OO that I would like. I didn't know BD had and removed it, interesting.
@Sean - I must say that the phrase "shot down" is a bit strong as you were very respectable about it, but the strong feeling was definitely conveyed and I was surprised at the time. Learning C++ and VB first as a student and THEN entering the ColdFusion arena as a professional, it IS painful to not have a constructor that is implicitly called. :-)
@Joshua, yeah, I figured it must be me :)
My background is also of many other languages, several of them OO, but I don't see much difference - beyond the extra typing - between this:
createObject("component","path.to.myCFC").init(myarg1,myarg2);
and this:
createObject("component","path.to.myCFC",myarg1,myarg2);
and that's about as good as you're going to get in terms of "automatic" calling, regardless of whether the constructor "name" is init() or myCFC() or whatever. So you'd save six characters when you have arguments and seven when you don't. Not a big deal. Especially when you have to type 28 characters in addition to the class type to create an object anyway.
If you want to save typing, write your own new() function that takes an arbitrary number of arguments and calls both createObject() and init() automatically for you.
Oh, the irony: the captcha text for this comment is 'bs'... :)
Unless,
They introduce new with the constructors.
<cfset myInstance = new com.company.Image('jpg') />
<cfset myInstance.drawLine(10, 10, 50, 50) />
But i'm only half serious, using init aint that bad.
PS: If they add new and the constructor must be defined as a method called init method then existing code would not break :)
Ya know, you could write a UDF called newCOmponent, that would let you do:
<cfset foo = newComponent("car").("ford","four wheel")>
This UDF would make a new car component and call init passing along the args you had sent to it.
Just an idea. :)
Ugh, I'm reading my Comment email top down, saw Dale's email, and not Seans, where he basically mentioned the same type thing. Sorry Sean!
@Sean & @Ray: For me, it's not a "save-me-five-keystrokes" deal, it's more about the fuzzy feeling inside knowing that I can create the object without passing any parameters and know it's ready to do business. i.e.:
MyFoo=CreateObject("component","foo");
And to know it's good to go as an empty (but initialized!) object. It feels un-OOP-ish (lol) to have to explicitly tell it to .init() for the creation of a new empty object and be sure that all its innards have been initialized properly, because of my comfort from other langs that have the official constructor that will do this.
Two more points: (a) This isn't a terrible deal to me. I'm just vocalizing it because the topic came up. (b) I haven't started USING ColdSpring yet, but I can appreciate from my reading about it, that this becomes a non-issue because of how ColdSpring handles the execution of init() for you. That's awesome. Outside of that context, though, the init() method feels like a good convention, but not like good OO.
Lol, I suppose this is good fodder for the "CF is not true OO" discussion. :-)