Wednesday 21 August 2013

Brad Wood makes an interesting feature suggestion for CFML

OK, having got today's Stack Overflow rant out of the way, here's the article I meant to write this morning. Or actually last night. Well actually "here's the text that someone else wrote that I meant to copy and paste in lieu of actually writing something". Here it is. CTRL-C, CTRL-V...

Redefining truthy and falsey values

Consider adopting some behaviors from languages such as JavaScript or Groovy which allow for more clever conditional statements to be constructed. Consider this ticket a discussion on whether this is even possible and what implications it would have. I assume this might also require an on/off flag such as the null support feature.
This table outlines a suggestion of how the following values would behave when cast to booleans:
Numberfalse if 0, otherwise true
Stringfalse if "", "false", or "no"; otherwise true.
Arrayfalse if empty, otherwise true
Structfalse if empty, otherwise true
This would allow for the full ternary version of the Elvis operator (Assuming full null support):
foo = null;
bar = foo ? foo : "default";
It would also simplify checking for the contents of structs and arrays:
myArray = [1,2.3];
if( myArray ) writeOut("Array has stuff");

myStruct = [];
if( !myStruct ) writeOut("Struct is empty");
I think these changes might be somewhat straightforward and mostly affect the Caster class, but most importantly:
  1. Do we want this in CFML?
  2. Would this have serious implications in backwards compatibility?
Other things to consider that are similar to Groovy would be Java Map, List and Iterator classes. True if not empty, or hasNext() is true.
Brad Wood added that to the Railo bug base a coupla days ago, as RAILO-2583 (and I've now raised it with Adobe too: 3616205). I asked Brad if I could plagiarise him with a view to encouraging discussion on the topic. And depending on what people think, raising a ticket for ColdFusion too.

So what do you think?

My default position on new ideas is to go "no". Why? Because one of my favourite movies is "12 Angry Men", in which Henry Fonda as Juror Number 8 made a specific point of voting against the tide to force the jury to spend more time thinking about things. I don't say "no" because I mean "no", it's because I want to think more before deciding "yes" (or, hey, sticking with "no").

In this case though I kinda wanted to come up with a reason to finally decide "no". This is because right from the outset I kinda creased my nose, and my gut instinct was "is it the right thing to do?" And if I'm asking that question, the answer is probably "no" (a variation on Betteridge's law of headlines, I guess).

However over the last day or so I've mulled and mulled, and I can't actually see any reason why this doesn't make sense, and would actually be quite handy in CFML. I don't think it's a stretch to consider empty values (be they null or an empty array or struct, etc) as false. Why not? I also think it could be possible to have an interface (concrete or notional) that allows CFC instances to declare whether they pass a null test (and accordingly a true/false test) too. Although that's perhaps a separate discussion.

I also don't think there are backwards compat risks here. One thing to consider is that people could conceivably have written code like this:

try {
    if (someVarWhichCouldBeNull){
      // true case
} catch (NullPointerException npe){
    // false case

And this code would stop working as intended if suddenly NULL was false. However I think anyone writing code like that should have already been shot, so they won't mind.

Equally one might have code thus:

try {
    if (someStringWhichMightHaveZeroLengthOrHaveValueTrue){
      // true case
} catch (NullPointerException npe){
    // false case

But, again... those people should have been put up against the wall already, so I don't think there's any need for anyone to worry about breaking their code.

So I think it's a safe change, and has merit. This Juror #8 is changing his vote to "yes".