I'm making sort of a series out of poking holes in the anti-ColdFusion ramblings of an admittedly biased blogger. Pro-PHP blogger Phil Parsons blogged about how ColdFusion is tragically slower than PHP and is therefore something we should all stay away from if performance is any kind of concern. Unless we want to connect to MS Exchange... maybe.
So his second example was object instantiation performance. Arguably, one of ColdFusion's weak points... but not something entirely unworkable. People who complain about this generally only do so because they don't know how to best use CFC's and, most especially, how to write them properly. Nowhere is this more apparent than in Mr. Parsons' components. If this is how he writes CFCs it's no wonder his employer has "to constantly make decisions NOT to use OO features of Coldfusion based on [sic] it's poor performance." (That quote is from his comments below the article).
You can download the source he uses in the article, so I'm not going to post that here. I will say that the primary critiques I have against them are things like the ungodly amount of white space, the silly variable creation in the pseudo-constructor and the amazing number of unnecessary expressions.
What I am going to show you is my version, and then I'll share my results.
Colony.cfc
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfcomponent displayName="Colony" output="false">
<cffunction name="init" output="false" returntype="Colony">
<cfargument name="cn" type="String" default="colony">
<cfscript>
colonyName = arguments.cn;
drones = arrayNew(1);
</cfscript>
<cfreturn this>
</cffunction>
<cffunction name="addDrone" output="false" returntype="void">
<cfargument name="drone" type="Drone" required="true">
<cfset arrayAppend(drones, drone)>
</cffunction>
<cffunction name="getDroneCount" output="false" returntype="numeric">
<cfreturn arrayLen(drones)>
</cffunction>
</cfcomponent>
1<cfcomponent displayName="Colony" output="false">
2
3 <cffunction name="init" output="false" returntype="Colony">
4 <cfargument name="cn" type="String" default="colony">
5 <cfscript>
6 colonyName = arguments.cn;
7 drones = arrayNew(1);
8 </cfscript>
9 <cfreturn this>
10 </cffunction>
11
12 <cffunction name="addDrone" output="false" returntype="void">
13 <cfargument name="drone" type="Drone" required="true">
14 <cfset arrayAppend(drones, drone)>
15 </cffunction>
16
17 <cffunction name="getDroneCount" output="false" returntype="numeric">
18 <cfreturn arrayLen(drones)>
19 </cffunction>
20
21</cfcomponent>
Drone.cfc:
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfcomponent displayname="Drone" output="false">
<cffunction name="init" output="false" returntype="Drone">
<cfargument name="m" type="String" required="true" default="">
<cfset message = m>
<cfreturn this>
</cffunction>
<cffunction name="getMessage" output="false" returntype="String">
<cfreturn message>
</cffunction>
<cffunction name="setMessage" output="false" returntype="void">
<cfargument name="val" type="String" required="true">
<cfset message = val>
</cffunction>
</cfcomponent>
1<cfcomponent displayname="Drone" output="false">
2
3 <cffunction name="init" output="false" returntype="Drone">
4 <cfargument name="m" type="String" required="true" default="">
5 <cfset message = m>
6 <cfreturn this>
7 </cffunction>
8
9 <cffunction name="getMessage" output="false" returntype="String">
10 <cfreturn message>
11 </cffunction>
12
13 <cffunction name="setMessage" output="false" returntype="void">
14 <cfargument name="val" type="String" required="true">
15 <cfset message = val>
16 </cffunction>
17
18</cfcomponent>
colony.cfm:
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<cfscript>
Colony = new objects.Colony("colony1");
start = getTickCount();
while (Colony.getDroneCount() < 10000) {
Colony.addDrone(new objects.Drone());
}
end = getTickCount();
writeOutput("Adding 10,000 Drones to the Colony took " & end-start & " miliseconds.");
</cfscript>
1<cfscript>
2 Colony = new objects.Colony("colony1");
3
4 start = getTickCount();
5 while (Colony.getDroneCount() < 10000) {
6 Colony.addDrone(new objects.Drone());
7 }
8 end = getTickCount();
9 writeOutput("Adding 10,000 Drones to the Colony took " & end-start & " miliseconds.");
10</cfscript>
And now for the really bad news:
While I managed to blow his unquestionably inflated time of roughly 600ms or more right out of the water, ColdFusion continues to have a weak spot around object instantiation. The best I could do was slightly less than half of what Mr. Parsons got. I manged to get this test down to 250-300ms. Still substantially slower than the 42ms he reported for PHP. So while Mr. Parsons was grossly exaggerating the problem, the problem yet persists. Even with the drastic improvements the ColdFusion team managed to pack into ColdFusion 9.0.1 over previous versions.
The question you have to ask yourself, at that point, is whether it really makes any difference. CFCs (and OO in general, really) are about maintenance, and there are ways you should use them and ways you shouldn't. Not knowing those rules, or worse knowing them and deliberately refusing to use them, and then presenting yourself as someone with something worthwhile to say on the subject is just plain dishonest. It's been years since I've worked on an application that was written without CFCs, and even the ones that were poorly done performed adequately. The ones that were written with CFC best practices in mind were actually extremely performant.
In other words, there's no reason for anyone's employer to refuse to use them due to performance or any other reasons but ignorance, poor design and (worst of all) hyperbole. It's no different than knowing you should be using arrays instead of lists, or that structures are passed by reference and arrays by value. Go ahead, it's OK. Use CFCs in your applications... just do it intelligently, keeping in mind what works and (most important) what doesn't. And use ColdFusion's built-in data structures to their maximum advantage: structures, queries, arrays, oh my! Use the scopes, too: server (far too often overlooked), application, session, request, variables, this, super, caller, etc. The list goes on and on.
Programming is a craft. Craft your applications wisely and you'll never go wrong (unless you're looking to trash-talk something using bad science and worse code).
Laterz!