Array or single element - varargs

Java indorduced the following in version 6 or 7 and i start to use it more and more. so i asked myself if this would be a good addition to CFML.

Take this example:

function test(MyCFC[] mycfcs, MyCFC mycfc) {
...
}

first argument is expecting an array of MyCFC and the second a single MyCFC.
So if i wanna pass a single MyCFC for the first argument, i have to do the following.

test([mycfc])

i have to wrap my cfc in a array so i can pass it. In java i can define the first argument as follows

function test(MyCFC... mycfcs, MyCFC mycfc) {
...
}

this allows me to pass in a single myCFC as first argument or an array of them and inside the function i always have an array.

This makes the argument more flexible.

we could also make lucee to accept always a single MyCFC even an array is expteced by default, without using that syntax.

  1. we already have access to the implicit/builtin Arguments variable, which lets you access these values in any way you want

  2. we already can wrap variables in an inline array very easily, e.g. call test([ mycfc1, mycfc2, mycfc3 ])

IMO this is not needed in CFML/CFScript since we have pretty good alternatives already and this addition will only clutter the language without adding much value.

p.s. if you use the varargs … then it must be the last parameter

1 Like

I’m somewhat split on it…

The main benefit to Java, IIRC, is that a varargs param will default to an empty array. CFML already has that ability. Therefore function (arg1, any... varargs) and function(arg1, varargs=[]) is equivalent from within the body of the function.

As a matter of style, I will say it makes the method call look cleaner without forcing the method to have to scan the arguments scope. withVarArgs(1,2,3) vs without(1, [2,3]).

I’d probably lean toward @21Solutions’ side though as it seems not enough reward for the effort at this point.

As @21Solutions already mentioned, Java’s varargs must be the last argument in the list so your example is wrong. It would need to be:

function test( String msg, MyCFC... mycfcs ) { ... }

This would be a function that takes a string arguments followed by zero or more MyCFC arguments:

test("one");
test("two", cfc1);
test("three", cfc1, cfc2);
test("four", cfc1, cfc2, cfc3);

and inside test there would be just two arguments with the types String and MyCFC[] respectively.

In CFML today we’d have to do:

function test( String msg, MyCFC[] mycfcs ) { ... }

This would be a function that takes a string arguments followed by an array containing zero or more MyCFC arguments:

test("one",[]);
test("two", [cfc1]);
test("three", [cfc1, cfc2]);
test("four", [cfc1, cfc2, cfc3]);

I’m not convinced that the variadic format is worth the effort. It can be confusing (your function calls seem to have an arbitrary number of arguments, your function itself only has one or two arguments – and the “arrayness” of the last argument is implicit) – and CFML already allows arbitrary arguments to function calls and provides a full arguments vector containing them all. You could argue “But the Java style gives you type checking!” which is true but mostly irrelevant: you could do type checking at run time if you wanted, or you could just interact with the argument values and let the CFML runtime trap any type errors (CFML is a dynamically typed language – it is not Java).

Java is actually worse in some ways, because when you want a variadic non-homogenous argument list, Java forces you to use Object... and then perform dynamic type checking and down-casting at runtime anyway! So you’re often forced to lose what little type safety Java provides and then you have to write extra code, compared to CFML, to “do the right thing” with your now-generic Object types!

1 Like

Funny how a few years later we sometimes see things differently. I was actually looking for a Java-like varargs now and re-found this post.

FWIW, my simple solution is to use arrayMerge with a new array, so my function which may accept either an array called items, or a bunch of individual items, now looks like this:

public numeric function add(required items) {

    if (!isArray(arguments.items)) {
        arguments.items = [].merge(arguments);
    }

    ...

One could also use arraySlice() if there are other arguments first, but in my cases there aren’t any.

Thought I’d share.

1 Like