Thursday, 19 September 2013

CFML Suggestion: being able to stipulate passing data by reference

G'day:
I'm just soliciting opinions about a potential feature request here. I'd like to be able to force CFML to pass arguments / parameters by reference rather than by value.

I wrote an article a while ago about "Complex data-types in CF, and how they're not copied by reference" which could be a reasonable primer if you're not already comfortable with the notion of references and how they work (or aren't used when they should be) in CFML.

In ColdFusion (but not in Railo) for some reason, arrays are always duplicated when they are passed as function arguments or tag parameters (incl. custom tag attributes); whereas data of other complex types are passed by reference (for all intents and purposes). Here's some quick code to demonstrate:

function arrayHandler(array){
    arrayAppend(arguments.array, "toru");
    writeDump(var={variablesScope=variables.array, argumentsScope=arguments.array}, label="Within arrayHandler()");
}

function structHandler(struct){
    struct.six = "ono";
    writeDump(var={variablesScope=variables.struct, argumentsScope=arguments.struct}, label="Within structHandler()");
}

array = ["tahi", "rua"];
struct = {four="wha", five="rima"};

writeDump(var=[array,struct], label="Before function calls");
writeOutput("<hr>");

arrayHandler(array);
writeOutput("<hr>");
structHandler(struct);
writeOutput("<hr>");

writeDump(var=[array,struct], label="After function calls");

On CF this outputs:
Before function calls - array
1
Before function calls - array
1tahi
2rua
2
Before function calls - struct
FIVErima
FOURwha

Within arrayHandler() - struct
ARGUMENTSSCOPE
Within arrayHandler() - array
1tahi
2rua
3toru
VARIABLESSCOPE
Within arrayHandler() - array
1tahi
2rua

Within structHandler() - struct
ARGUMENTSSCOPE
Within structHandler() - struct
FIVErima
FOURwha
SIXono
VARIABLESSCOPE
Within structHandler() - struct
FIVErima
FOURwha
SIXono

After function calls - array
1
After function calls - array
1tahi
2rua
2
After function calls - struct
FIVErima
FOURwha
SIXono

And on Railo, there is a key difference (I've trimmed the struct part out of this dump for the sake of brevity):
Before function calls
Array
1
Array
1
stringtahi
2
stringrua

Within arrayHandler()
Struct
ARGUMENTSSCOPE
Array
1
stringtahi
2
stringrua
3
stringtoru
VARIABLESSCOPE
Array
1
stringtahi
2
stringrua
3
stringtoru

After function calls
Array
1
Array
1
stringtahi
2
stringrua
3
stringtoru

Notice how in ColdFusion the array in the function is not the same one as the array in the calling code: changes to the array in the function do not affect the calling code. Whereas in Railo they're the same arrays: changes to the array in the function also change the array in the calling code.

Right, so we're on the same page now.

I think ColdFusion is doing the wrong thing here, but I also think it's too late in the day to "fix" it.

What I'd like to be able to do instead is to have some sort of annotation to say "pass this thing as a reference", eg:

function arrayHandler(required &array array){
    
}

Where &array signifies and array reference, rather than the array itself.

Initially it might seem like this is limited to only arrays, but I also see it as being useful for functions which manipulate & "return" strings as well. Strings are passed by value, and strings can get rather large. So it would be useful to also be able to pass strings by reference too, I think.

Also when using threads, for reasons best know to itself, ColdFusion passes everything into a thread by value:

struct = {one="tahi", two="rua"};

thread name="t1" struct=struct {
    struct.three = "toru";
}
thread action="join" name="t1";

writeDump(struct);

Yields:
struct
ONEtahi
TWOrua

Railo is again more sensible here:
Scope
STRUCT
Struct
ONE
stringtahi
THREE
stringtoru
TWO
stringrua

I'd like to make CF be sensible here too.

This would not be functionality that would get use every day (well: for arrays it would, for me, I guess), and is not groundbreaking, but would be useful I think?

Thoughts?

I've raised a ticket for this: 3638235.

--
Adam