ColdFusion 9's IsNull() Works On Non-Struct Objects
When I first did my exploration of ColdFusion 9's isNull() function, I definitely came away thinking that the isNull() function was merely a short-hand, convenience notation for the existing structKeyExists() function. The other day, however, when blogging about creating proxy objects, I was dealing with a situation in which the base value that I was checking might not always be an object with a struct-like interface. In a scenario like that, my first instinct was to check for "struct-ness" before I checked for "null-ness:"
<cfif (
isStruct( someValue ) &&
!isNull( someValue.someKey )
)>
<!--- Do some conditional logic here... --->
</cfif>
As you can see here, I'm using the short-circuiting nature of ColdFusion's conditional statements in order to check that the value was both a struct and that a key off of that struct was non-null. On a whim, I decided to see if I could remove the isStruct() condition. And, much to my delight, it turns out that isNull() works on simple values just as well as it works on structs.
<!--- Create a string value. --->
<cfset myString = "Boo ya!" />
<!--- Check for a property of it. --->
String Key Null: #isNull( myString.someKey )#
As you can see, we are checking for a property of a string value (which is typically a no-no in ColdFusion). When we run the above code, we get the following output:
String Key Null: YES
It correctly determines that the given key path cannot be gotten off of the given base value. It doesn't matter at all that the base value is a simple value and not a struct (or struct-like object).
Now, like I said, it was sort of my assumption that isNull() was a short-hand for structKeyExists(); however, if we try to rewrite the previous statement using structKeyExists():
<!--- Create a string value. --->
<cfset myString = "Boo ya!" />
<!--- Check for a property of it. --->
String Key Exists: #structKeyExists( myString, "someKey" )#
... we get the following ColdFusion error:
You have attempted to dereference a scalar variable of type class java.lang.String as a structure with members.
As you can see, when we explicitly treat the string as a struct, we get an error; but, if we let isNull() do the key-path checking, the data type doesn't matter.
I know this is a really minor point, but if you think that isNull() is nothing more than a short-hand for structKeyExists() - just as I sort of did - then you really aren't leveraging isNull() to its full potential. ColdFusion 9's isNull() function allows you essentially confirm both data type and key path existence within a single conditional statement.
Want to use code from this post? Check out the license.
Reader Comments
Ben,
I love nuances like this one. Thanks for teasing it out. I had the same take that you did.
-Mark
@Mark,
Heck yeah - it's all about understanding what the language can really do ... and leveraging it :)
Is this a new behavior in CF9 or has it existed previously? I'd love to use this instead of StructKeyExists(), but can't if it's not backwards compatible.
@Justin,
The isNull() function is new in CF9. For CF8, you have to use structKeyExists() or isDefined().
For what it's worth, I use IsDefined("struct1.struct2.struct3.key") all the time without first checking struct1, struct2 or struct3. I can't recall ever using StructKeyExists. But then, that's just me. StructKeyExists probably compiles to much more efficient Java.
@WebManWalking,
To be honest, I don't use isDefined() enough to know the rules behind it. That's cool that you can use arbitrary data types as well. I know there are some differences between isNull() and isDefined(), specifically when checking for scope existence:
www.bennadel.com/blog/1773-IsNull-vs-IsDefined-For-ColdFusion-9-Scope-Detection.htm
It seems that isNull() isn't quite like structKeyExists() and it isn't quite like isDefined(). It's some magical beast unto itself :)
You know how Evaluate() translates a string (with possible #-sign substitutions if it's a string literal) into a variable reference, right? Well basically, for any string, if IsDefined(string) is true, Evaluate(string) will not crash.
In the IsDefined("struct1.struct2.struct3.key") example, I don't really care why it failed: struct1 may not exist, or struct1 may not be a struct, or struct1.struct2 might not exist, etc, etc. All of those possibilities result in the IsDefined() call returning false.
I think you've hit on something with IsNull(). It's sort of similar to a Java HashMap or TreeMap. If you try to get() a key you never put(), the get() returns false. It's like IsDefined("ref") with quotes is equivalent to IsNull(ref) without quotes.
I should have said, if you try to get() a key you never put(), the get() returns null.
@WebManWalking,
Exactly... except for scope evaluation.