Saturday 4 April 2015

CFML: using an array as an argument collection

Here's a quick one for Lucee users (this does not apply to ColdFusion).

I discovered yesterday (? maybe the day before) that as well as taking a struct for an argument collection; Lucee will also take an array. This is a piece of the argument collection puzzle that has been missing from CFML for quite some time. That said,  I dunno how long Lucee/Railo has supported this..? It's def only "new to me", rather than "new", per se.

Here's an example:

// arrayAsArgumentCollection.cfm

function f(required z, y, required x){

echo("Control: using a struct<br>")
args = {x="value for x", z="value for z"}

echo("Test 1: simple array<br>")
args = ["value for z", null, "value for x"]

echo("Test 2: sparse array<br>")
args = []
args[3] = "value for x"
args[1] = "value for z"

Here I have a simple function which just dumps its arguments. Note that its first and third arguments are required; its second is optional (never do this in real life: do all the required arguments first) I run three tests:

  • demonstrating a baseline of using a struct as an arguments collection: we're all familiar with that.
  • Using a fully-populated array to demonstrate passing all ordered arguments into the function.
  • Trying to demonstrate there's no smoke and mirrors going on here. I populate only the array elements I need (so no second element in this array; the second argument is optional, remember). I also populate the array in the reverse order: the third arg's value, then the first (not that it matters to the array).
And this all works fine on Lucee:

Nice one.

ColdFusion just errors if I try this (note the CFML above is Lucee-only anyhow; I mean the general technique just errors on CF).

That is good, sensible work from the Lucee Team.

To demonstrate what isn't either good or sensible work, we have the ColdFusion way of dealing with ordered arguments in an argument collection. They pretend that a struct's keys are ordered... if the keys are numeric. I kid you not. FFS. Here's an example:

// orderedStruct.cfm

function f(required z, y, required x){

writeOutput('Test 3: using an "ordered" struct<br>');

args = {3="value for x", 1="value for z"};

This also "works" on both CF and Lucee:

I dunno what's worse here. That Adobe implemented this as a solution or - get this - someone actually requested this way of dealing with it. Sigh.


I found references to how this came to be in ColdFusion's CFML, from comments in an article on Ben Nadel's blog: "ColdFusion Ordered ArgumentCollection Behavior Depends On ColdFusion Version And Invocation Context". Don't worry so much about the article, focus on the comments, especially when Elliott starts trying to explain it.

Oh well.

Anyway: a good win for Lucee doing things for CFML the right way.