This might be old news, but it's something I didn't know until today. Railo supports function return values and arguments of type array-of-something, eg:
function acceptArrayOfSamples(required Sample[] samples){
    // etc
}
Sample[] function returnArrayOfSamples(){
    return [new Sample(), new Sample()];
}
Where sample is a CFC, eg:
//Sample.cfc
component {
}
It also works (kinda) for inbuilt types too, like strings and numerics.
I had a look at how well this stuff works, writing these test functions:
// functionsToTest.cfm
private any function acceptArrayOfSamples(required Sample[] samples){
    return samples;
}
private Sample[] function returnArrayOfSamples(required array samples){
    return samples;
}
private any function acceptArrayOfStrings(required string[] strings){
    return strings;
}
private string[] function returnArrayOfStrings(required array strings){
    return strings;
}
private any function acceptArrayOfNumerics(required numeric[] numerics){
    return numerics;
}
private numeric[] function returnArrayOfNumerics(required array numerics){
    return numerics;
}
private any function acceptArrayOfStructs(required struct[] structs){
    return structs;
}
private struct[] function returnArrayOfStructs(required array structs){
    return structs;
}
These functions either accept an array of various types (Samples, strings, numerics, structs), or return same.
I've written some unit tests to see how well this lot works:
// TestArraysOfObjects.cfc
component extends="mxunit.framework.TestCase" {
    public void function beforeTests(){
        variables.arrayOfSamples    = [new Sample(), new Sample()];
        variables.arrayofSubSamples    = [new SubSample(), new SubSample()];
        variables.arrayofNotSamples    = [new NotSample(), new NotSample()];
        variables.arrayOfStrings    = ["array", "of", "strings"];
        variables.arrayOfNumerics    = [-1, 2.2, pi()];
        variables.arrayOfStructs    = [{one="tahi"}, {two="rua"}, {three="toru"}, {four="wha"}];
        include "./functionsToTest.cfm";
    }
    public void function testAcceptArrayOfSamples(){
        acceptArrayOfSamples(arrayOfSamples);
    }
    public void function testReturnArrayOfSamples(){
        returnArrayOfSamples(arrayOfSamples);
    }
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function testAcceptArrayOfSamples_withStrings(){
        acceptArrayOfSamples(arrayOfStrings);
    }
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function testReturnArrayOfSamples_withStrings(){
        returnArrayOfSamples(arrayOfStrings);
    }
    public void function testAcceptArrayOfSamples_withSubSamples(){
        acceptArrayOfSamples(arrayOfSubSamples);
    }
    public void function testReturnArrayOfSamples_withSubSamples(){
        returnArrayOfSamples(arrayOfSubSamples);
    }
    
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function acceptArrayOfSamples_withNotSamples(){
        acceptArrayOfSamples(arrayOfNotSamples);
    }
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function testReturnArrayOfSamples_withNotSamples(){
        returnArrayOfSamples(arrayOfNotSamples);
    }
    public void function testAcceptArrayOfStrings(){
        acceptArrayOfStrings(arrayOfStrings);
    }
    public void function testReturnArrayOfStrings(){
        returnArrayOfStrings(arrayOfStrings);
    }
    public void function testAcceptArrayOfNumerics(){
        acceptArrayOfNumerics(arrayOfNumerics);
    }
    public void function testReturnArrayOfNumerics(){
        returnArrayOfNumerics(arrayOfNumerics);
    }
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function testAcceptArrayOfNumerics_withStrings(){
        acceptArrayOfNumerics(arrayOfStrings);
    }
    /**
    * @mxunit:expectedexception expression
    */ 
    public void function testReturnArrayOfNumerics_withStrings(){
        returnArrayOfNumerics(arrayOfStrings);
    }
    public void function testAcceptArrayOfStructs(){
        acceptArrayOfStructs(arrayOfStructs);
    }
    public void function testReturnArrayOfStructs(){
        returnArrayOfStructs(arrayOfStructs);
    }
}
Where Sample.cfc is as per above, and SubSample.cfc and NotSample.cfc are as follows:
// SubSample.cfc
component extends="Sample" {
}
// NotSample.cfc
component {
    
}
To summarise the tests, what I've done is:
- for the functions expecting/returning a Sample array, passed in arrays of Samples, SubSamples, NotSamples, strings. The latter two are expected to error, and do;
- for the functions expecting a string array, just tested with a string array
- for the functions expecting a numeric array, tested with both a numeric array and a string array (the latter ones - correctly - error)
- for the functions expecting a struct array, tested just with a struct array
So the following tests fail:
- passing an array of strings to a function expecting... an array of strings;
- same with the function expecting a numeric array, it fails when it correctly receives an array of numerics;
- same with structs.
Update:
As Rory observes in his comment below: this has all been fixed in Lucee. Nice one.This is a handy feature, but it's incomplete. I've gotta go do some work now, but I'll check if there's a bug report for this, and raise one if not. And I will cross-reference back here either way. I'll also check to see if there's a ticket to implement this in ColdFusion, and raise / cross-reference accordingly.
That's it.
--
Adam

