Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Jesse Dearing
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Jesse Dearing

The Safe Navigation Operator Checks Both Left And Right Operands In ColdFusion

By
Published in

Historically, I've always thought of the safe navigation operator - ?. - as checking the left operand in an expression before continuing to evaluate the right operand. However, by sheer accident, I stumbled upon the fact that the safe navigation operator appears to check both the left and right operands. And, this appears to work in both Adobe ColdFusion and Lucee CFML.

Given the expression:

foo?.bar

I've always thought that the safe operator meant: If foo is defined, return the evaluation of foo.bar; and, if foo is undefined, return null.

But, it seems that this mental model is incomplete! Based on my accidental testing, it seems that this will return null if either foo or foo.bar is undefined.

To see what I mean, take a look at this ColdFusion code:

<cfscript>

	// Output the CFML runtime version.
	if ( server.keyExists( "lucee" ) ) {

		writeDump( "Lucee CFML #server.lucee.version#" );

	} else {

		writeDump( "Adobe ColdFusion #server.coldfusion.productVersion#" );

	}

	// Missing PARENT (safely navigating FROM an undefined reference).
	// --
	// Here, ColdFusion is checking the LEFT OPERAND (kablamo) for "nullness". This is
	// how my mental model for the safe navigation operator was working.
	writeDump({
		value: variables.kablamo?.foo
	});

	// Missing KEY (safely navigating INTO an undefined key).
	// --
	// Here, ColdFusion is checking the RIGHT OPERAND (foo) for "nullness". This is an
	// unexpected outcome according to my previous mental model.
	writeDump({
		value: variables?.foo
	});

</cfscript>

In the first one, the safe navigation operator is short-circuiting the expression if the left operand, kablamo, is undefined. But, in the second one, the safe navigation operator is short-circuiting the expression if the right operand, foo, is undefined.

Before I ran this code, if I was asked to tell you what would happen, I would have assumed that the second one would have thrown an error for an undefined struct key. However, if we run this in both Adobe ColdFusion 2018 and Lucee CFML 5.3.7.48, we get the following output:

Two undefined values and no errors in both Adobe ColdFusion 2018 and Lucee CFML 5.3.7.48

As you can see, both expressions return null / undefined in both Adobe ColdFusion and Lucee CFML. This was surprising!

What this means is that in my previous post on translating sparse Go JSON payloads, I could have replaced calls like this:

translateAppearanceModel( deviceModel.appearance ?: nullValue() )

... with calls like this:

translateAppearanceModel( deviceModel?.appearance )

... replacing the Elvis operator (null coalescing operator) with the safe navigation operator.

If this only worked in Lucee CFML, I would have considered it a bug. But, given the fact that it works in both CFML runtimes, I guess this is just how it's supposed to work; and that my mental model for it has always been insufficient. Which is great to know!

Want to use code from this post? Check out the license.

Reader Comments

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel