Revisiting CFML Operators In Lucee
Operators are ubiquitous. As developers, we use them every day, and maybe even in every line of code.
Why is it then, I never seem to find the time to revisit these language essentials? Perhaps it’s because I’m guilty of “going with what I know works”; maybe it’s the act of re-training my thought processes which is difficult; either way, it can certainly do no harm to have a refresh occasionally.
It can sometimes take a new language, product, or version of something to trigger that refresh. Recently I’ve been doing a lot of VueJS, and switching between JS and CFML was enough to trigger a need to remind myself of the fundamentals. This blog, therefore, looks into revisiting CFML Operators in Lucee.
Strict Comparison Operator
Take this comparison operator ===
for instance. In Vue, my linting setup would always moan at me if I used ==
in place of ===
, and rightly so; In JS, ==
returns true
if the operands are equal; but ===
only returns true
if the operands are equal AND of the same type.
Naturally, I’d start back on my CFML based API, and end up using ===
in the same conditions (as let’s face it, cfscript and javascript syntax these days are awfully close), but the Lucee version of this operator works differently; it returns true
if the operands are the same object in memory. Cue lots of head-scratching from me.
Ternary Operator
Although the main reason for revisiting CMFL Operators in Lucee is to remind me of the fundamentals, there is another reason to go back and look at the basics and that is actually laziness. Are there any new tricks so I can physically write less code? Or better yet, more concise, performant, and hopefully more readable code?
Whilst I’ve been using it for a while now, the ternary operator has definitely worked its way into my go-to toolbox. My new favourite thing is replacing if/else
statements with a single ternary operator.
Take for example this bog-standard statement:
if( someCondition ){ foo = 1; } else { foo = 2; };
With a ternary operator, we can drop this down to a single declaration:
foo = someCondition ? 1 : 2;
which I find pretty neat and clear. It also helps prevent a lot of nested if/else
statements, especially when assigning values to variables based on a condition.
We can replace:
if( someCondition ){ foo = 1; if ( somethingElse ){ bar = 3; } else { bar = 4; } } else { foo = 2; };
with
foo = someCondition ? 1 : 2; bar = someCondition && somethingElse ? 3 : 4;
which I find a lot cleaner and clearer.
Null Coalescing Operator
Otherwise known as the “Elvis operator”. How does this compare to a ternary operator?
// Example 1 - Ternary foo = someValue ? 1 : 2; // Example 2 - Elvis foo = someValue ?: 2;
They look pretty close but will do quite different things.
If someValue
exists, then a ternary operator will pick 1
or 2
dependent on the outcome of the condition, as we’ve seen above.
If someValue
doesn’t exist, i.e, is Null
undeclared, then that line would rightly throw an error.
The Elvis operator, on the other hand, will look at the left-hand condition, and if it exists, will use it. If it doesn’t, will then use the right-hand value.
So that means we can take much more verbose code like:
if( isDefined("someValue") ){ foo = 1; } else { foo = 2; }
and replace with:
foo = someValue ?: 2;
This can actually be really helpful in navigating unknown structs, where you’re looking for something deep and nested – i.e, transversing a JSON result from an API;
req = { foo = 1 }; result = req?:foo?:bar?:baz; writeDump(result);
This will safely return req.foo
– but if it had further children, would continue until it hit an undefined variable.
Hopefully, this blog has helped to refresh your knowledge on CFML Operators in Lucee and these couple of examples might encourage you to revisit operators soon!