Under the Hood - ColdFusion Array
It's very easy to iterate (loop) over a simple array variable. It's also trivial to get a specific element. But when the array is returned from a function, you can't just ask for getFoo()[x]. Or can you?
A ColdFusion Array
Let's start out with a simple variable of type array.
<cfset foo[1] = "A" />
<cfset foo[2] = "B" />
<cfset foo[3] = "C" />
<cfset foo[4] = "D" />
<cfset foo[5] = "E" />
<cfdump var="#foo#" />
Getting any element of the array is simple:
Function of returntype Array
Now let's create a function that returns the array:
<cfreturn foo />
</cffunction>
<cfdump var="#getFoo()#" />
No difference, right? Wrong. We can't retrieve a particular element of the array in the same manner as the simple variable.
Normally we'd just assign the value of the function to another variable and run the code as usual.
Calling on the underlying Java
Many of us (CF developers) tend to forget that there's Java under all that CFML. I remembered someone else had blogged about being able to call Java String functions directly on ColdFusion String variables within <cfoutput>
<cfoutput>
#y.toUpperCase()#
</cfoutput>
So it would stand to reason that a ColdFusion array is converted to some Java object that can contain multiple elements. And if it's a Java object, then there has to be some way to access each element.
Something like a getter in a bean.
Some way to get each item in the object.
#getFoo().get(3)#
</cfoutput>

Iterating over the returned array
It's easy to loop (iterate) over the simple array variable:
#x#: #foo[x]#<br />
</cfloop>
2: B
3: C
4: D
5: E
Now we can use the same syntax directly with the function without having to create another variable to reference the function's value.
But did you notice something different between the two outputs?
- foo[3] output C
- getFoo().get(3) output D
The reason for this is that ColdFusion begins indexing elements at position 1, while Java begins at 0.
So we'll have to take that into consideration when looping over the array.
<cfloop index="x" from="1" to="#arrayLen(getFoo())#">
#x#: #getFoo().get( x-1 )#<br />
</cfloop>
</cfouput>
So there's one last hurdle to clear here. The get() method is a Java method and we're trying to pass a ColdFusion variable to it. Java doesn't know what to do with the CF variable, so it throws an error.
Since we know we can pass a numeric value to the function get(), we just have to make sure that CF passes the actual value of x to Java.
<cfloop index="x" from="1" to="#arrayLen(getFoo())#">
#x#: #getFoo().get( evaluate( x-1 ) )#<br />
</cfloop>
</cfoutput>
2: B
3: C
4: D
5: E
Update per the Comments
I guess I was still in a CF mindset when trying to pass x to get(). I should be using JavaCast() to tell Java what kind of value get() would be receiving.
<cfloop index="x" from="1" to="#arrayLen(getFoo())#">
#x#: #getFoo().get( javaCast("int", x-1 ) )#<br />
</cfloop>
</cfoutput>
Thanks Mark, Sean and Ben.
Under the Hood
I Google'd around for a minute trying to find out which Java object was under the ColdFusion array and found this post by Christian Cantrell from 2003.
According to him, a ColdFusion array is actually a Java Vector. So that means that we can call any Vector method on a ColdFusion array.
Now, instead of using a ColdFusion array function:
I can call a Vector function on the value returned from the ColdFusion function:
or I can call the Vector function directly on the original variable:
So why would I want to do this?
Really, I have no idea. I was working on another post for the OO CF Primer and started thinking too much when I got to a part that talks about retuning an array from a Bean via a getter.
I know that you would NOT want to use this syntax when calling a function that actually runs some data logic or database access. Especially if you're looping over the array of results. That would cause you to run the function's logic or database calls for each iteration of the loop.
However, if the function is just returning the value of a variable that was set by some other process, like a property of a Bean, then you could use this syntax to avoid creating another variable or to keep with the a.b.this.that syntax of the OOP world.
But at least if you didn't know before, now you know that a ColdFusion array is a Java Vector.
And knowing is half the battle.
*flees*









That was a fun read!
DW
getFoo().get( javaCast("int", x-1 ) )
I think the scenario you came up with is a great example of why you would want to use this. Being able to tread a method return as an array without an intermediary variable is huge! I can't tell you how many useless variables I have had to used because of this one fact.
Also, another really useful one is the ability to add an entire array to another one in a single step:
<cfset ARRAY1.AddAll( ARRAY2 ) />
The one thing to be really cautious of is the data types being used. ColdFusion does it's best to guess the data type you want to use, but it doesn't always get it properly. You are using evaluate(), but I am not sure if evaluate() is required to return a number??
Rather, I would suggest using JavaCast() as this is exactly what it was defined for.