Copy link to clipboard
Copied
Hi,
i use this code in CF2023
<cfscript>
params = {
field1 = true
};
foo(args=params);
void function foo(required struct args) {
if (arguments.args?.field2) {
writeOutput("entra");
} else {
writeOutput("non entra");
}
}
</cfscript>but i receive error
in first time, after only java.lang.NullPointerException
In CF2025 continue with previuos error
Am I doing something wrong or is this a bug?
I think ColdFusion is behaving as expected. As
arguments.args.field2
does not exist, the safe-navigation operator (?.) returns null as the value of arguments.args?.field2.
Then the code
if (arguments.args?.field2) {
}
tells ColdFusion to cast a null to a boolean, hence the error.
Copy link to clipboard
Copied
Paolo, some good news is that there is a very simply single tweak that will get your code working.
First, though, I don't think you'll have found that code to have ever worked (as you expect) in any CF version, right? To be clear, the result of using the safe nav operator has never itself been a boolean. It's always been an "undefined" result (if the operator on the right doesn't exist). And it's because of this that your error occurs, because of course an IF test expects an expression which evaluates to boolean.
You can even prove this without all your code (there's nothing about your if being in a method that changes things). This first example shows how the dump of the result is indeed "undefined":
<cfscript>
params = {field1 = true};
writedump(params?.field2);
</cfscript>
Then as for trying to use the result as a boolean, this next example shows (more simply) how doing that fails with the same error you show:
<cfscript>
params = {field1 = true};
if (params?.field2) {
writeOutput("entra");
}
</cfscript>
Finally, if you're wanting your code to "run" even if that field2 is undefined, you could tweak it simply by adding the elvis operator to the end of the line, which tells CF that if the result of the expression is indeed undefined, then it should be set to a default provided on the right side of the elvis operator. Tweaking my example above, this outputs your string:
<cfscript>
params = {field1 = true};
if (params?.field2?: true) {
writeOutput("entra");
}
</cfscript>
And implementing that in your code requires changing only that if line:
<cfscript>
params = {
field1 = true
};
foo(args=params);
void function foo(required struct args) {
if (arguments.args?.field2?:true) {
writeOutput("entra");
} else {
writeOutput("non entra");
}
}
</cfscript>
And it outputs the "entra" string. Of course, if you prefer it to return the "non entra" string, change the if line to end with false instead.
Let us know what you think.
Copy link to clipboard
Copied
Hi Charlie, thanks for your clarification but your example has true, instead false
So, correct is:
<cfscript>
params = {field1 = true};
if (params?.field2 ?: false) {
writeOutput("enter");
} else {
writeOutput("don't enter");
}
</cfscript>Furthermore, if the variable (used for form fields) also has an empty string value, you should use a solution like this:
if ((params?.field2==true) ?: false) {
writeOutput("enter");
} else {
writeOutput("don't enter");
}I'm a bit concerned about using safe-navigation together with the ternary/elvis operator as it affects the reading/understanding of the code in my opinion.
What do you think?
Copy link to clipboard
Copied
I'm a bit concerned about using safe-navigation together with the ternary/elvis operator as it affects the reading/understanding of the code in my opinion.
What do you think?
By @Paolo Olocco
I agree with you, @Paolo Olocco .
The safe-navigation and elvis operators each condenses multiple functionalities together, including the underlying assumptions. That is, they increase the code's complexity. In so doing, they make the code more difficult to debug and to maintain than if you had used the operator-less version of the code.
Copy link to clipboard
Copied
I think first that you missed my final sentence, 'Of course, if you prefer it to return the "non entra" string, change the if line to end with false instead.'
I think second that if you're opting to use the safe nav operator, you've already bought into modern app development mechanisms like it, such that adding use of the Elvis operator should not be denigrated for affecting readability. You will find that many online resources discussing cf's safe nav operator also show using Elvis with it.
It not only makes logical sense but it solves the very problem you have presented. I'm frankly surprised to see bkbk concur with you.
Still, it's your code and you both have free will. I do lament that his reply was chosen as an answer. He merely said in fewer words what I offered with elaborated explanation of things, which you thanked me for clarifying. Do you think it not worthy of being marked as another answer? (Indeed, did you choose bkbk's reply after mine to be an answer, or did he?)
Copy link to clipboard
Copied
Charlie, my answer, though you lament that it is "merely said in a few words", does respond to both questions asked in the original post, namely:
Your "elaborated explanation of things" is certainly helpful. However, it contains mistakes.
Paolo has pointed out one of the mistakes. That is, your params?.field2?:true (incorrect) in place of the correct params?.field2?:false. In coding, the standard default boolean for a non-existent variable is false.
There is a second mistake. You suggest arguments.args?.field2?:true, which evaluates to true when the key field2 does not exist in the structure arguments.args. That is incorrect for the reason I've already given.
Finally, I not only agree with Paolo, I think his opinion is profound. His concerns that using safe-navigation together with the elvis operator can affect the reading and understanding of code are real and well-founded. There are occasions, such as in Paolo's function when, for example,
if ( isNull(arguments.args.field2) or !arguments.args.field2 ) {
// false
}
or
if ( !structKeyExists(arguments.args, "field2") or !arguments.args.field2 ) {
// false
}
would be more readable and easier to understand than
if ( arguments.args ?. field2 ?: false ) {
}
This does not mean the combination safe-navigation+elvis is bad. It is elegant when used where optionality is intentional. However, it increases the semantic density, hence the entropy, of the code. As such, it can be less readable and more difficult to understand.
Copy link to clipboard
Copied
As often, we'll have to agree to disagree.
Copy link to clipboard
Copied
Hi Charlie, sorry, but I initially missed your final sentence. I was referring to the example because those are the parts that immediately catch the eye. That said, I didn't validate the correct answer; I didn't even know it existed until now.
Copy link to clipboard
Copied
I think ColdFusion is behaving as expected. As
arguments.args.field2
does not exist, the safe-navigation operator (?.) returns null as the value of arguments.args?.field2.
Then the code
if (arguments.args?.field2) {
}
tells ColdFusion to cast a null to a boolean, hence the error.
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more