Adobe ColdFusion Elvis Operator Struggles With Nested Array References
In Lucee CFML, the Elvis Operator (null coalescing operator) is quite powerful. In fact, it can often replace the Safe Navigation operator when access values on deeply-nested structures. In contrast, the Elvis Operator in Adobe ColdFusion is much more problematic. And, in fact, I just ran into another rough edge in the ACF implementation. It seems that the Elvis operator has trouble with nested array references.
Nested Struct references seem to be fine in both Lucee CFML and Adobe ColdFusion. Both engines will happily return the empty-string for this nonsense expression:
( foo.bar.baz.kablamo ?: "" )
However, if we were to replace one of those intermediary undefined keys with an undefined array index, Adobe ColdFusion would break. Let's take a closer look and how it breaks at the various object paths.
In my Dig Deep Fitness app, when you perform a workout, I overlay the previous sets on top of the current sets. Of course, if this is the first time you've performed an exercise, there's no prior data to overlay. As such, I end up with an empty array; which I was attempting to safely consume with the Elvis operator.
The code looked something like this (heavily boiled down):
<cfscript>
recentWorkouts = [
{
sets: [
{ weight: 100, reps: 12 }
]
}
];
writeDump( recentWorkouts[ 1 ].sets[ 1 ].weight ?: "" );
</cfscript>
Here, I'm trying to access the first weight
of the first sets
of the first recentWorkouts
. Notice that both recentWorkouts
and sets
is an array.
If we run the above "happy path" code (where everything is defined) in both Adobe ColdFusion and Lucee CFML, we get the following:
- Lucee: 100
- ACF: 100
Now, let's try commenting-out the contents of the sets
:
<cfscript>
recentWorkouts = [
{
sets: [
// { weight: 100, reps: 12 }
]
}
];
writeDump( recentWorkouts[ 1 ].sets[ 1 ].weight ?: "" );
</cfscript>
If we run this code in both engines, we get:
- Lucee:
[empty string]
- ACF:
[empty string]
So far, both engines are successfully handling the undefined sets
index. Now, let's try commenting-out the sets
entirely:
<cfscript>
recentWorkouts = [
{
// sets: [
// // { weight: 100, reps: 12 }
// ]
}
];
writeDump( recentWorkouts[ 1 ].sets[ 1 ].weight ?: "" );
</cfscript>
If we run this code in both engines, we get:
- Lucee:
[empty string]
- ACF: Element SETS is undefined in a CFML structure referenced as part of an expression.
Now let's try commenting-out the first workout:
<cfscript>
recentWorkouts = [
// {
// // sets: [
// // // { weight: 100, reps: 12 }
// // ]
// }
];
writeDump( recentWorkouts[ 1 ].sets[ 1 ].weight ?: "" );
</cfscript>
If we run this code in both engines, we get:
- Lucee:
[empty string]
- ACF: The system has attempted to use an undefined value, which usually indicates a programming error, either in your code or some system code. Null Pointers are another name for undefined values.
As you can see, Lucee CFML continues to operate properly as we comment-out items farther up the chain of nested values. Adobe ColdFusion, on the other hand, starts to throw different errors depending on the level of nesting.
ASIDE: Not catching this in the code was my bad - I was sloppy in testing my code after making changes.
I'm so used to using the Elvis / Null Coalescing operator in Lucee CFML because it is so robust and powerful. I have to remember that it has many more rough-edges and gotchas in Adobe ColdFusion. Especially, as it were, with array references.
Want to use code from this post? Check out the license.
Reader Comments
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →