Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

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

By Ben Nadel on
Tags: ColdFusion

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!



Reader Comments

What has two thumbs and hopes you leave a comment? This Guy! (Ben Nadel).

Post A Comment

You — Get Out Of My Dreams, Get Into My Blog
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.