Skip to main content
Ben Nadel at dev.Objective() 2015 (Bloomington, MN) with: Andy Matthews and Tim Cunningham and Matt Gifford and Dave Ferguson and Dan Wilson
Ben Nadel at dev.Objective() 2015 (Bloomington, MN) with: Andy Matthews Tim Cunningham Matt Gifford Dave Ferguson Dan Wilson

Core String Functions Will Accept Null / Undefined Values In ColdFusion

By
Published in Comments (2)

In ColdFusion, you can have null / undefined values. You can't directly reference those null values or you'll get a null reference error (NRE); but, you can pass around null values using return-value propagation or the safe-navigation operator. This sometimes leaves me unsure as to how ColdFusion will handle a specific null-value scenario. A while back, I looked at ColdFusion's core decision functions; and it turns out, they all play nicely with undefined values. Today, I wanted to look at the core string functions in ColdFusion to see how they handle null / undefined values.

In a lot of old ColdFusion code, you'll see very cautious traversal of object paths using logic that looks like this:

<cfscript>

	if ( variables.keyExists( "value" ) && len( variables.value ) ) {

		// ... do something with value ....

	}

</cfscript>

In this case, we're using the structKeyExists() function to see if the property value exists before subsequently inspecting its length so we don't throw a null reference error. In modern ColdFusion, we can often use the Elvis operator (?:) and / or the safe navigation operator (?.) to simplify our logic. However, since ColdFusion hasn't always played nicely with null / undefined values, it's not always clear what happens when ColdFusion consumes a null value in a function call like len().

It turns out, ColdFusion does exactly what we would hope that it does: treat the value as "empty". That allows us to simplify the above code like this:

<cfscript>

	if ( len( variables?.value ) ) {

		// ... do something with value ....

	}

</cfscript>

It turns out that a lot of the native string-oriented functions in ColdFusion do exactly what we would hope that they do. Here's a quick sanity check - I'm going to consume a null / undefined value in a bunch of ColdFusion functions that assume strings:

<cfscript>

	try {

		echoVersion();
		echoValue( "val: [#val( variables?.undefined )#]" );
		echoValue( "trim: [#trim( variables?.undefined )#]" );
		echoValue( "len: [#len( variables?.undefined )#]" );
		echoValue( "ucase: [#ucase( variables?.undefined )#]" );
		echoValue( "lcase: [#lcase( variables?.undefined )#]" );
		echoValue( "left: [#left( variables?.undefined, 1 )#]" );
		echoValue( "right: [#right( variables?.undefined, 1 )#]" );
		echoValue( "mid: [#mid( variables?.undefined, 1, 1 )#]" );
		echoValue( "listLen: [#listLen( variables?.undefined )#]" );
		echoValue( "listFirst: [#listFirst( variables?.undefined )#]" );
		echoValue( "listRest: [#listRest( variables?.undefined )#]" );
		echoValue( "getToken: [#getToken( variables?.undefined, 1 )#]" );
		echoValue( "encodeForHtml: [#encodeForHtml( variables?.undefined )#]" );
		echoValue( "encodeForHtmlAttribute: [#encodeForHtmlAttribute( variables?.undefined )#]" );
		echoValue( "encodeForUrl: [#encodeForUrl( variables?.undefined )#]" );
		echoValue( "asc: [#asc( variables?.undefined )#]" );
		echoValue( "hash: [#hash( variables?.undefined )#]" );
		echoValue( "toString: [#toString( variables?.undefined )#]" );
		echoValue( "canonicalize: [#canonicalize( variables?.undefined, true, true )#]" );
		echoValue( "concatenation: [#( variables?.undefined & variables?.undefined )#]" );
		echoValue( "equality: [#( variables?.undefined == variables?.undefined )#]" );
		echoValue( "inequality: [#( variables?.undefined != variables?.undefined )#]" );

		// Error: Can't cast string to boolean.
		// echoValue( "logical: [#( variables?.undefined && variables?.undefined )#]" );

	} catch ( any error ) {

		writeDump( error );

	}

	// ------------------------------------------------------------------------------- //
	// ------------------------------------------------------------------------------- //

	/**
	* I output the current ColdFusion product version.
	*/
	public void function echoVersion() {

		var version = ( server.keyExists( "lucee" ) )
			? "Lucee CFML #server.lucee.version#"
			: "Adobe ColdFusion #server.coldfusion.productVersion#"
		;

		echoValue( version );
		echoValue();

	}

	/**
	* I output the given value on its own line.
	*/
	public void function echoValue( any value = "" ) {

		writeOutput( value & "<br />#chr( 10 )#" );

	}

</cfscript>

If we run these in Lucee CFML 6.2, we get the following output:

Lucee CFML 6.2.1.122

val: [0]
trim: []
len: [0]
ucase: []
lcase: []
left: []
right: []
mid: []
listLen: [0]
listFirst: []
listRest: []
getToken: []
encodeForHtml: []
encodeForHtmlAttribute: []
encodeForUrl: []
asc: [0]
hash: [D41D8CD98F00B204E9800998ECF8427E]
toString: []
canonicalize: []
concatenation: []
equality: [true]
inequality: [false]

If we run these in Adobe ColdFusion 2023, we get the following output:

Adobe ColdFusion 2023,0,13,330759

val: [0]
trim: []
len: [0]
ucase: []
lcase: []
left: []
right: []
mid: []
listLen: [0]
listFirst: []
listRest: []
getToken: []
encodeForHtml: []
encodeForHtmlAttribute: []
encodeForUrl: []
asc: [0]
hash: [null]
toString: []
canonicalize: []
concatenation: []
equality: [YES]
inequality: [NO]

I tried running this on BoxLang v1.0.0, but get an error:

java.lang.VerifyError: Inconsistent stackmap frames at branch target 2282

As you can see, ColdFusion basically treats null / undefined inputs the same way it would treat the empty string; which is exactly what we would hope that it does when attempting to simplify our logic. In particular, I'm excited to know that I can use len() and val() to safely consume a lot of potentially undefined values in my ColdFusion control flow.

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

Reader Comments

50 Comments

While I like most of it (variables?.undefined) I can't say I'm a fan of hash() returning a value. I can see potential issues there. I think CF gets it "more better" here. It was funny, I immediately said "noooooo" as I was scrolling to change to "ah, that's better" seeing the CF result.

For me, it's ACF for work and 100% Lucee for non-work or anything "new" like a personal biz. (And by "100%" Lucee I mean "if I'm not using non-CFML" like a JS framework.)

16,015 Comments

@Will,

Yeah, the hash() one struck me as strange too on the Lucee side. I wonder if it's converting to an empty string; or maybe the string literal null. I'll see if I can sus-out which thing it's doing.

re: side-project stuff, I'm the opposite - Lucee at work, ACF in personal life. That's primarily because I use managed hosting. If I actually knew something about server management, I would have more options.

Are you managing your own servers?

Post A Comment — I'd Love To Hear From You!

Post a Comment

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