Tuesday, February 06, 2007

ColdFusion Array : pass by reference or Value.

Ben rightly pointed out in my last post that since ColdFusion array are always passed by value, the second technique can not be used if you want to build the array over multiple method calls. In each of the function call, ColdFusion will create a copy of the array passed and that cost (cost of creating a new instance and copying old array to new one) might even exceed the cost of appending string.

ColdFusion array is one unique data structure in ColdFusion. Unique in the sense that this is the only data structure that is passed by value and not by reference. I do feel it is a limitation sometimes but thats legacy and can not be changed. (You would not want us to break your code. Would you? ;) )

There does exist one hack if you absolutely need to pass the array by reference. Here is a code snippet that uses pass by reference.

<cfset x = ArrayNew(1)>
<cfloop from=1 to=5 index=i>
<cfset Arrayappend(x,"something")>

<cfset x = CreateObject("java", "java.util.ArrayList").init(x)>
<cfset foo(x)>
<cfset foo(x)>
<cfset x[8] = "after the method call">
<cfset x[9] = "end of method call">
<cfset foo(x)>
<cfdump var="#x#">

<cffunction name="foo">
<cfargument name="arr">
<cfset ArrayAppend(arr, "from function")>

So what did we do here? We created an ArrayList from the ColdFusion array. Since ColdFusion Array is an implementation of java.util.List, almost all Array functions work on all implementations of java.util.List. And this list implementation will not be passed by value but will be passed by reference. Thats the power of using java in ColdFusion !


Ben Nadel said...

Rupesh, I agree. Passing the array by value does seem like a limitation. I like the stuff you have above... but be careful, if memory serves, this works on 99% of things, but bombs for ArrayResize(). But other than that, this is good solution.

Rupesh Kumar said...

That is why I said **almost** all and not ALL.

Rupesh Kumar said...

Most of the time, you would call resize pretty much soon after creating the array when you know that your array is going to store this many element. You can do the same thing for the ArrayList that you created.
So you can use

<cfset myarr = CreateObject("java", "java.util.ArrayList").init(1000)>
<cfset myarr.addAll(x)>
<cfset x = myarr>

Ben Nadel said...

Word up, I didn't mean to come off sounding attacking. I was just clarifying that the *almost* I think only is ArrayResize(). I think the initialization technique you just commented on is a great idea. I didn't realize that you could init with a size. Thanks for the hot tip!

Rupesh Kumar said...

Hey Ben.. you didn't. I am sorry if I sounded that way :)

Anonymous said...

Hope to see a CALLBY argument in the next CF version:
<CFARGUMENT CALLBY="value|reference|default" ...>

Anonymous said...

thanks for posting this. i just stumbled over this "feature" and was about ready to throw my laptop out the window... ;)