ColdFusion and Pass by Reference versus Value

So this is something I’ve blogged about before, but as it recently burned a friend of mine, and got some pushback from folks on Twitter, I thought I’d raise the issue again.

When working with ColdFusion, any complex data type (structs, CFCs, queries, COM/JavaObjects, did I miss one?) will be passed by reference, not by value.

For those of you who took English Lit 1 instead of Comp Sci 101, all this means is that these variables are not copied when sent to a function. In other words, when I do:

<cfset newThing = changeIt(oldThing)>

Under normal circumstances, if changeIt manipulates values in oldThing and does a return on it, my newThing will have the manipulated values and oldThing will be just fine.

But with complex data, like structures, you are actually passing the exact same object (a reference). That means any changes inside the UDF will be reflected on the original object.

As an example:

<cfscript> function fubar(data) { arguments.data.name = "Britney"; return arguments.data; } </cfscript>

<cfset s = {}> <cfset s.name = “Paris”> <cfset s2 = fubar(s)> <cfdump var=”#s#” label=”S”> <cfdump var=”#s2#” label=”S2”> </code>

I’ve created a simple structure with one key. I’ve created a UDF that changes the value and returns a ‘new’ struct (right?). But look at what the dumps show:

Fail! Luckily enough it is easy to fix:

<cfset s2 = fubar(duplicate(s))>

The duplicate function will create a deep copy of the structure before sending it to the UDF.

Now, here is where things get interesting. Did you notice I didn’t mention arrays in my list of complex objects? Well, they are indeed copied by value, not by reference, but, if you include a structure as part of the array, the structure portion will be copied by reference. Check this out:

<cfscript> function fubar2(data) { arguments.data[1] = 9; arguments.data[2].gender = "female"; arguments.data[3] = "Not so goofy"; return arguments.data; } </cfscript>

<cfset a = []> <cfset a[1] = “42”> <cfset a[2] = {}> <cfset a[2].gender = “male”> <cfset a[3] = “Goofy”> <cfset b = fubar2(a)> <cfdump var=”#a#” label=”A”> <cfdump var=”#b#” label=”B”> </code>

I’ve got an array with 3 values. Values 1 and 3 are strings, value 2 is a structure. My new UDF, fubar2, changes all 3 values. And the result?

As you can see, the simple values weren’t changed in the original, but the embedded structure was. As before, using a duplicate around ‘a’ would solve the problem.

But is it a problem? Well certainly if you aren’t expecting it, but the fact that structs and other complex objects pass by reference isn’t “wrong” per se, and it can be useful as well. Just don’t forget it.

Raymond Camden's Picture

About Raymond Camden

Raymond is a developer advocate looking for his next gig. He focuses on JavaScript, serverless and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support.

Lafayette, LA https://www.raymondcamden.com

Comments