Skip to main content
Ben Nadel at CFCamp 2023 (Freising, Germany) with: Hanna Eckert
Ben Nadel at CFCamp 2023 (Freising, Germany) with: Hanna Eckert

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

By
Published in Comments (7)

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.

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

Reader Comments

449 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"))
{
...
}
15,902 Comments

@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.

449 Comments

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?

15,902 Comments

@Charles,

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

15,902 Comments

@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.

449 Comments

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...

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