Core String Functions Will Accept Null / Undefined Values In ColdFusion
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
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.)
@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 literalnull
. 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 →