tracker issue : CF-4203472

select a category, or use search below
(searches all categories and all time range)
Title:

Add deepcopy param to duplicate()

| View in Tracker

Status/Resolution/Reason: Open//

Reporter/Name(from Bugbase): Bradley Wood / ()

Created: 11/16/2018

Components: Language

Versions: 13.0

Failure Type: Others

Found In Build/Fixed In Build: /

Priority/Frequency: Normal /

Locale/System: / Platforms All

Vote Count: 1

In Lucee, there is a second, optional param to the duplicate() function which defaults to true.  When I pass false, it will only duplicate the top level and all nested objects are set by reference.  Basically akin to how structCopy() works except you can use it on CFC instances and you actually get a new CFC instance with all the same methods and variables as the original CFC without needing to use createObject() or new.

Here is a code snippet showing how this works on Lucee.  This is very useful for frameworks like ColdBox that want to skip the performance issues of creating large numbers of identical objects by cloning a template object.  A deep copy is not acceptable since the CFC may have references to many other CFCs inside of it which should not be duplicated.

https://trycf.com/gist/1d782052ee871e38efcde42a4121a2da/lucee5?theme=monokai

{code}
// Construct a CFC
oQuery = new Query();
// Decorate it with some things
oQuery.foo = 'bar';

// Create a shallow clone of the CFC into a new CFC
oQueryCopy = duplicate( object=oQuery, deepCopy=false );

// The copy has everything including foo
dump( oQueryCopy );
{code}

Attachments:

Comments:

+1 would be a really useful performance feature.
29940 | November 16, 2018 03:54:01 PM GMT
Wouldn't it be more OOP to be able to add a clone method to a CFC to disctate what it is to clone an object of that CFC? EG: // C.cfc component { function init(A a, B b) { variables.a = a; variabless.b = b; } function clone(){ return new C(variables.a, variables.b.clone()); // reference of a is fine; b needs to be a new object though } } This is aI think more obvious, plus has more flexibility as it allows the component to define its own cloning behaviour, rather than a headless function to make that decision globally. Lucee's approach seems to betray a sorta procedural thinking in its language design, and not sure it is where CFML ought to have gone to address this. FWIW, I think the enhancement is a good one, but just not how to implement it. Also from a clean code perspective... adding flag params to a function to make it do a second thing is generally an indication of a code smell. And it certainly is in this case.
Comment by Adam Cameron
29941 | November 16, 2018 07:07:36 PM GMT
Sorry, dind't quite finish transfering my thoughts down onto the page there. In addition to the above, the base Component class implements a clone method which does what duplicate currently does, plus when one calls duplicate on an object, it calls the object's clone method. The method doesn't need to be called clone... could be called duplcate in fact perhaps. Makes it more obvious what's going on?
Comment by Adam Cameron
29942 | November 16, 2018 07:42:36 PM GMT