I was messing around with some array-building code the other day - I don't even recall what it was for now - and I thought if I want to concatentate two arrays, why do I need to do this:
lowNumbers = ["tahi", "rua", "toru", "wha", "rima", "ono"]; // the ones I remember
higherNumbers = ["whitu", "waru", "iwa", "tekau"]; // the ones I always have to look up
numbers = lowNumbers;
numbers.addAll(higherNumbers);
writeDump([lowNumbers,higherNumbers, numbers]);
Why can't I just do this:
numbers = lowNumbers + higherNumbers;
Now I realise that as of ColdFusion 10 (and some version of Railo: not sure which), arrayAppend() also optionally acts as an arrayConcatenate() function, but I'm on CF9 so that's no help. However it got me thinking... isn't just using the + operator more sensible? I jumped onto repl.it to see if Ruby allows this: and it does. Good: a precedent as been set here.
So I think it makes a certain amount of sense to be able to use the + and += operators on both arrays and structs. + works between two objects, returning a third; += works on the first operand, updating it inline. This language progression is like how we used to have to do this:
st = structNew();
structInsert(st, key, value);
Then we could set a struct key/value with the [] operators:
st = structNew();
st.key = value;
Now we can just use the {} operator to create a struct using literal syntax:
st = {key=value};
So to concatenate arrays we used to need to do it by hand, then use a function, but now simply using an operator makes sense.
Further to this, how about the equality operators? There's no reason this shouldn't work:
if (someArray == someOtherArray){
// do stuff
}
(This should do a value-level comparison, and for doing a reference level one, we'd need the usual === operator too).
The == operator should work on any object that implements an equals() method (or better: implements a Comparable interface).
This got me thinking, which other operators are out there which CFML could benefit from. Here's a few I found that seem pretty handy:
Operator | Function | Precedent | Comment |
---|---|---|---|
<=> | Compare | Groovy | Analogous to CFML's compare(). Should work for any object for which there's an appropriate compareTo() method (see Comparable). |
==~ | Equals pattern | Groovy | Returns true if the regex in the second operand matches the first operand, eg:
'a' ==~ '[a-z]'
would be true |
?. | Safe navigation | Groovy | This is best demonstrated with an example:So rather than erroring because a.e doesn't exist, it gracefully returns null. Nice. This saves a lot of sequential structKeyExists() calls, or (grim) an isDefined() call. |
?? | Null-coalescing | C# | This returns the first operand if its not null, otherwise the second. A use-case for this is for a kind of <cfparam>-lite sort of thing: defaulting variables which might (not) be set. Railo has implemented the Groovy version of this which is ?:, but I think that's a misleading construct as it looks identical to the already-extsing ternary operator, which is a different thing, and it's confusing to have two quite different operators which look the same. However I guess a precedent has been set with Railo, so perhaps deferring to ?: might be a reasonable thing to do. |
.. | Inclusive Range | Ruby | This is trickier as it creates a "range" which is a concept CFML doesn't have. However the concept is an interesting one. The range 1..10 is basically a sequence of values from 1-10. If one was to convert it to an array, one would have [1,2,3,4,5,6,7,8,9,10]. Ranges can be used for sequences, eg:
for (i in range){
// do stuff
}
//or
range.each(callback);
Or in conditional statements, eg:
if (examScore in 50..100){
//pass
}else{
//fail
}
and that sort of thing. |
... | Exclusive Range | Ruby | As above except the range is up to but not including the uppper boundary. |
What do you think? Are there other operators in other languages that would be good for CFML to co-opt? I'd much rather CFML adopt things like this than more wizards that write JavaScript for us.
--
Adam