ColdFusion Performance V – The Inheritance Tax
Seems like the British government is not the only body to tax inheritance. ColdFusion will tax you heavily when you extend objects.
I’ve conducted a small test that instantiated 10,000 objects. First, I tried a 3 level inheritance. One object extends another which extends another. The extending objects do nothing. They just sit there with empty bodies, fiddling their thumbs.
I then went for a ‘normal’ 2 level inheritance: one object extends another. And last a single object which extends nothing.
The first case of 3 level inheritance took double the processing time of no inheritance. The 2 level inheritance was dead in the middle. Seems like every time you extend an object you’ll be taxed, even if the extended objects don’t do much!
This confirms my view that in most cases composition of objects is better than inheritance. Instead of extending an object, we should first consider if it might better our cause to pass that object as an argument to a method or make it a property of the parent. In any case, extension, though it has its place, is a less flexible approach than composition.
You can download my test case here. Just unzip the file and place the directory on your ColdFusion server. Note the processing times reported for each test case.
April 6th, 2007 at 1:34 am
Now go back and run the tests again, but this time turn on “Trusted Cache” in CFAdministrator.
April 7th, 2007 at 3:17 am
ugh, regardless of OO practice, 10k cfcs is way above the norm eh? CFC instantiation is expensive whether composition or inheritance is in use. Passing a object to a method of another object is not really composition, eh? Composition is the ‘has a’ relation ship, A has a B so A is composed of properties and a B. Two cfcs are still created, so at 10k iterations, still very expensive.
DK
April 7th, 2007 at 9:20 pm
Douglas,
Remember that a busy site might bet more than 10K requests in a day, and some might get that in an hour. It all ads up and make up how many pages a single server can serve up.
Harel
April 7th, 2007 at 9:26 pm
Michael, sorry – with trusted on or without, the 3 level inheritance takes a heavy toll….
April 7th, 2007 at 11:49 pm
Douglas,
Couple more things: Yes passing as argument wasn’t said describing composition – it was merely another way of ‘doing it’.
And, in some cases you can cache an object which is a property of another, saving on instantiation.
April 8th, 2007 at 2:30 am
Doing my own tests on the matter, I found that with trusted cache turned on the difference in performance was about 5% per step, or more of a “sales tax” than an inheritence tax.
Given that, it really comes down to the question of whether or not inheritence makes sense for your application. For example, in the Datum ORM system, each business object is actually two objects, one a “hidden” object that contains all of the auto-generated “scaffolding”, and the “visible” object which is inherited from that, and which lets the developer override any of the auto-generated functions.
While there’s a small performance hit involved in this pattern, it’s balanced out in two ways:
1) It’s flexible, allowing the developer a great deal of control while still allowing the auto-generated code to be rebuilt and extended whenever there’s a configuration file change.
2) It minimizes object creation and parameter passing.
While composition of objects may seem like a better arrangement, you in fact have to create that second object. Do the loop test, and you’ll see that creating two objects takes twice as long as creating one. Who’d have thought?
Not only that, but if the first object is a facade for the second, you’re going to spending a semi-significant amount of time passing parameters and results between objects, (which your empty object tests didn’t account for) again eating into your theoretical performance gain.
In short, you’re better off structuring your application in ways that make sense. Inheritence is a tool. Composition is a tool.
Just choose your tools wisely.
April 8th, 2007 at 11:25 pm
Michael,
I think my point was missed here. I use extension all the time, in the same scenario you describe. It’s a good and useful tool as is composition. My test was regarding 3 levels extensions. Where you have an object that extends another, and that one extends yet another. I would have expected, in an ideal world, that the compiled object will not bring with it 3 object instantiation penalty with it, but it does. (I’ve added the 2 level extension to the test as an after thought but my original one involved no extension vs 3 level one).