duplicate() is bad for your (object's) health
June 1, 2007 · 31 Comments
ColdFusion 8 brings a lot of enhancements, both large and small, and it's interesting to see what gets some people excited. Andrew Powell thinks that being able to duplicate a CFC is the most important new feature in ColdFusion 8. I've already commented on that blog post but I thought I'd elaborate and talk about why I think this particular feature is dangerous and misguided. I really hope that this is just a temporary aberration in the public beta build and that the ColdFusion team remove this ability and restore the CFMX 7 behavior: duplicate() on a CFC should throw an exception. "What?", you say, "but we've been asking for the ability to duplicate() CFCs for ages!" Yes, yes, I know... but have you actually thought about what it means?As it stands, calling duplicate() on a CFC produces a full, deep copy of a CFC. It's quite a common design idiom to have references to other objects within any given object. If you duplicate such an object, you will create duplicates of all the objects it references - a full, deep copy. Now look at Model-Glue and Transfer: both of these frameworks create objects that contain references back to the core framework object. In both cases, the core framework object is a singleton - only one instance is supposed to exist. In Model-Glue, the event context contains a reference back to the core ModelGlue framework object (several other objects also follow this model). In Transfer, each generated TransferObject contains a reference back to the core Transfer framework object. I expect Mach II and Reactor and some other frameworks behave the same way. It's a common idiom. Duplicate one of these and you have a pretty serious problem: you suddenly have a full, deep copy of the entire framework object tree in your newly minted object! Ouch! With Transfer, for example, you'll now have a separate copy of the cache in each of your duplicated objects and you'll start to get subtle problems with the integrity of your data. Something that seemed like a simple operation - copying a transient object - suddenly turns into an extremely hard-to-debug problem with random data corruption in your application! Ouch! Ouch! So why do you actually want duplicate() in the first place? The most common reason I've heard so far is that createObject() is "slow" so it would be great if you could just create one object and then duplicate it to produce new objects. This assumes duplicate() is faster than createObject(), right? And why do you think it would be? createObject() just creates a new object and runs the pseudo-constructor. duplicate() on the other hand would have to allocate space and copy all of the elements of the original object recursively. I think duplicate() would be slower than createObject(), especially now that ColdFusion 8 has made incredible improvements in performance, especially around creating new objects. I ran some tests. I created a simple.cfc that has just a small init() method that sets two variables and two getters for those variables. Then I timed 1000 createObject() calls. About 50ms. Then I timed 1000 creations plus calls to the init() method. About 60ms. Nice. What about duplicate()? You think it'll be faster? Well, 1000 duplicate() calls took about 3 seconds. Yes, you read that right: 3000ms. Still want duplicate() on CFCs?