Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Andy Allan
Ben Nadel at CFUNITED 2009 (Lansdowne, VA) with: Andy Allan@fuzzyorange )

The Elvis Operator Can Be Chained Multiple Times In A Single Expression In Lucee CFML 5.3.3.62

By Ben Nadel on
Tags: ColdFusion

In Lucee CFML, the "Elvis operator" - ?: - is a binary operator that returns the first operand if it is non-null; otherwise, it evaluates and returns the second operand. I haven't used the Elvis operator all that much, so I am still getting used to how it works. And, historically, I've only ever used it once in a single expression. The other day, however, I had a scenario where I wanted to use it several times in a single expression; and, I was happy to find that it works exactly as you might hope in Lucee CFML 5.3.3.62.

To see what I mean, take a look at this trite example:

<cfscript>
	
	// The Elvis operator can be chained several times in a single expression.
	result = ( nullValue() )
		?: nullValue()
		?: nullValue()
		?: nullValue()
		?: "fall-back value"
	;

	echo( "Result: #result#" );

</cfscript>

Obviously, this expression makes no sense; but, it demonstrates that the ?: operator can be chained together multiple times within a single expression. And, when we run the above ColdFusion code, we get the following output:

Result: fall-back value

As you can see, the ?: operator kept evaluating its second operand until it hit one - "fall-back value" - that was non-null.

The reason this came up for me was that I had an API response object that reported error messages in a variety of ways. And, instead of being graceful in the way that I was inspecting the response, I just wanted to heavy-hand the approach with the Elvis operator in conjunction with the Safe-Navigation operator to find the relevant error codes:

<cfscript>

	apiResponse = {
		errors: {
			transaction: {
				key: "info.number"
			}
		}
	};

	// I had an API response object that could report several different types of errors
	// and I didn't want to build a lot of logic about picking the response apart. So,
	// I used the safe-navigation operator in conjunction with the Elvis operator to
	// try and locate the known structures.
	error = ( apiResponse?.errors?.validation?.token )
		?: apiResponse?.errors?.validation?.field
		?: apiResponse?.errors?.transaction?.key
		?: "unknown"
	;

	echo( "Error: #error#" );

</cfscript>

Here, I'm using the Safe-Navigation operator to just blindly reach into the API response, understanding that the Safe-Navigation operator will return null if it can't find the desired object-query. Then, I use the Elvis Operator to continually "fall back" to other potential error locations. And, ultimately, I just use a back-up value if I can't locate the error.

And, when we run the above ColdFusion code, we get the following output:

Error: info.number

In retrospect, I had no reason to believe that the Elvis operator couldn't be chained multiple times in a single expression. After all, other binary operators like || and && can be chained like this. However, sometimes things just don't connect in my mind until I see them on paper. And, now I can clearly see that the Elvis operator can be chained multiple times within a single expression in Lucee CFML 5.3.3.62. This works particularly well in conjunction with the Safe-Navigation operator.



Reader Comments

Ben. What does this operator do:

?.

Is it replicating this:

if(StructKeyExists(apiResponse,"errors") AND  StructKeyExists(apiResponse.errors,"validation") AND StructKeyExists(apiResponse.errors.validation,"token"))
{
...
}
Reply to this Comment

@Charles,

That's exactly right. ?. is the Safe-Navigation operator, which will traverse the given path/property and return null if the given value does not exist. You can think of it like this -- a?.b -- is akin to:

try {
	return( a.b );
} catch ( any error ) {
	return( null );
}

... where it will try to access property b on object a; and, it is it not here, it will return null.

Reply to this Comment

Ben. Is the Safe-Navigation operator a Lucee only thing or does it work in ACF? I have never seen it used before.

It looks amazing. It's going to save me so much coding. No more excessive use of StructKeyExists(), although, theoretically I could use IsDefined(), but for some reason, I don't like using the latter. Someone told me that it's slower than StructKeyExists()? But, I guess we are talking milliseconds and in any case:

StructKeyExists(apiResponse,"errors") AND  StructKeyExists(apiResponse.errors,"validation") AND StructKeyExists(apiResponse.errors.validation,"token")

Is probably slower to parse than:

IsDefined(" apiResponse.errors.validation.token")

But I love the efficiency of:

apiResponse?.errors?.validation?.token

I am really looking forward to using this and I am using CF2018, as well, so I should be good to go?

Reply to this Comment

@Charles,

I believe that it is in Adobe ColdFusion as well. But, I'm not 100% sure on that. It also exists in TypeScript.

Reply to this Comment

@Ben,

Sorry, I think I have to amend that last comment. I am not sure that it exists in TypeScript -- but it can be used in parts of Angular (in its templates). But, I think that is Angular-specific.

Reply to this Comment

Yes. I often see you use it, in your Angular tutorials, so I guess it must work?

I know it doesn't exist in JS, so I would be interested to see what Angular converts it to, behind the scenes, at build time...

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
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.