The Elvis / Null Coalescing Operator Can Sometimes Replace The Safe Navigation Operator In Lucee CFML 5.3.6.61
Yesterday, when I was listening to the latest episode of the Modernize or Die Podcast, Brad Wood said something that I had not heard before: that the Safe Navigation operator can usually be replaced with the Elvis / Null Coalescing operator in Lucee CFML. I had always just assumed that without the safe navigation syntax, undefined keys would still throw null-reference errors, regardless of whether or not the Elvis operator was involved. As it turns out, Brad was right! Though, it only works if the given expression does not contain a method call. Since this was news to me, I thought it was worth a quick demo in Lucee CFML 5.3.6.61.
As a quick recap, the Safe Navigation operator allows you to safely traverse an object graph without throwing null-reference errors by using ?.
instead of .
when drilling down through object keys:
foo?.bar?.baz
If any of the keys along the way do not exist, the overall expression returns null
instead of throwing an error.
The Elvis / Null Coalescing operator (?:
), on the other hand, allows you to provide a fallback value for an expression that returns a null
value:
foo?.bar?.baz ?: "fallback value"
Now, what Brad is saying is that in this previous expression, I can actually remove the Safe Navigation operator and just use the Elvis operator. To demonstrate, here's a tiny ColdFusion script:
<cfscript>
echo( "Foo exists: " & variables.keyExists( "foo" ) );
echo( ". " );
echo( foo.bar.baz ?: "Null value fallback" );
</cfscript>
In this small demo, foo
doesn't exist. And, it's where I would normally use the Safe Navigation operator. However, since we are also including the Elvis operator, the previous ColdFusion script results in the following output:
Foo exists: false. Null value fallback
As you can see, even though foo
doesn't exist, we can still side-step null
reference errors by using the Elvis operator to provide a fallback value.
This is pretty cool! But, be aware that it appears to breakdown if the left-hand expression contains a method call. For example, if we call this ColdFusion code:
<cfscript>
echo( "Foo exists: " & variables.keyExists( "foo" ) );
echo( ". " );
echo( foo.bar.baz() ?: "Null value fallback" );
</cfscript>
... which is the same as above, except that our last object reference is .baz()
, not .baz
, we get the following ColdFusion error:
variable [foo] doesn't exist
It doesn't matter that the Method invocation operator (()
) is on the last object reference - it could be anywhere in the left-hand expression and the outcome is the same.
This is true even if the method being invoked exists:
<cfscript>
echo( foo().bar.baz ?: "Null value fallback" );
// ------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------- //
public void function foo() {
// No-op.
}
</cfscript>
In this case, the foo()
function exists, but returns null
. And, when we run this code, we get the following ColdFusion error:
No matching property [bar] found
It's really cool that the Elvis operator can stand-in, so to speak, for the Safe Navigation / Null Coalescing operator in simple expressions - thanks Brad! However, just be aware that this does break down in more complex expressions. Of course, you can always use the Safe Navigation operation in conjunction with the Elvis operator in those cases.
Want to use code from this post? Check out the license.
Reader Comments
what, no performance benchmarks? :)
I've forever wished I could use JS syntax for this...
I hadn't considered using the elvis operator to mimic this behavior. Cleaver. Unfortunately, it does not work in Adobe CF. Another (useful) example of where Lucee shines.
@Zac,
Ha ha :D Not this time.
@Chris,
Yeah, Lucee CFML is pretty grand. That said, the safe-navigation operator is in TypeScript if you ever go that route for your JavaScript.
@All,
On a related note, I just realized that my mental model for the safe navigation operator has been incomplete! I always thought it evaluated the left operand when deciding whether or not to evaluate the right operand. However, it appears to look at both:
www.bennadel.com/blog/4017-the-safe-navigation-operator-checks-both-left-and-right-operands-in-coldfusion.htm
Brad's recommendation is fine ("skip Safe Navigation operator & just use the Elvis operator") if you develop only for Lucee and have no expectation of your code being cross-compatible with Adobe.
foo?.bar?.baz ?: "fallback value"
works with CF2016-2021 as well as Lucee, but you can't skip directly to solely using the Elvis operator with ColdFusion. 😞NOTE: I returned this article while refreshing myself on the syntax and to further test. The info regarding the safe navigation operator should be added to CFDocs. (I've started using the Elvis operator and it really reduces logic while still being readable. Thx!)
@James,
It's funny you bring this up. I've been heavily updating my blogging platform lately, which runs on Adobe ColdFusion 2021 (currently); and, I think I was bit by this very thing! I tried to jump right to the
?:
and I got some null-reference errors..... unless I'm thinking about JavaScript / ES2021 🤔 I know I was trying to do this somewhere just recently and had to go back and add all the safe-navigation operators.
It's best to avoid (as commented here two years later):
www.bennadel.com/blog/4231-fundamental-differences-in-elvis-operator-between-adobe-coldfusion-and-lucee-cfml.htm
SUMMARY: Using Adobe ColdFusion, if
foo.bar.baz
exists & can be evaluated as falsey, it will use the fallback instead of the actual value.RECOMMENDATION: Be intentional & use a longer form ternary operation.