Passing a null named argument hides outer bindings by the same name

Description

Example:

Stacktrace:

boxlang a2d245a94be7e66c8186540c14728b5b45573445

Activity

Show:

Brad Wood November 1, 2024 at 5:09 AM

The compat module now handles this.

Brad Wood October 14, 2024 at 9:44 PM

So this really has nothing to do with functions and argument default values, and really boils down to null support. In CF, a null variable is ignored and CF pretends it doesn’t exist (with the exception of structKeyList()). Enabling null support in CF causes it to “see” null variables as a real live existing variable.

This behavior can be summed up anywhere there are 2 or most scopes like so:

On Lucee and Adobe, that returns arguments because they ignored the local.test variable and kept searching in other scopes until they found arguments.test. When you enable null support, they return null.


In BoxLang, we’ve made the default (and only) behavior one that recognizes null variables as existing in all cases. We have a transpiler shim that rewrites structKeyExists() calls to use isNull() instead so they can work the same. But this doesn’t affect unscoped variable lookups, which is really the source of the issue. Boxlang always returns null for the above code because it recognizes null variables so local.test is always found first. This also explains how and why BoxLang resolves the default value of the function param.

I don’t think there is a way we can “transpile” our way out of this one, so I’ll ponder on the best way to approach it. I’m not a fan of adding overhead to every variable lookup to check if we’re in a CF file or Boxlang file and then modifying the null check based on that.

David Rogers October 11, 2024 at 10:23 PM
Edited

I think the behavior differs in the null case, where an argument is explicitly set to null, and that argument is used as part of a default initializer. I agree that in the non-null case the shadowing is correct.



Brad Wood October 11, 2024 at 10:12 PM

After a quick test, it would appear Adobe matches BoxLang’s approach.

Adobe and BL both use the named argument over the variable’s scope.

Brad Wood October 11, 2024 at 10:07 PM

This seems correct to me. In ColdFusion, argument default values can point to another argument being passed in. i.e.

So, if param2 isn’t passed, it will default to the value passed for param1. So in your case, you’re passing an actual parameter called ZZZ which has a value of null. When the default expression for v is evaluated, it does a variable resolution on ZZZ based on the current context, and finds arguments.ZZZ (which is higher in the lookup order than variables.ZZZ) . The exception happens when trying to invoke a function that is null.

We need to fix the error message so it say something like, “you cannot invoke null as a function” but BoxLang’s behavior itself seems correct to me. Lucee’s behavior is what seems nonsensical.

Fixed
Pinned fields
Click on the next to a field label to start pinning.

Details

Assignee

Reporter

Fix versions

Priority

Sentry

Created October 11, 2024 at 9:17 PM
Updated November 1, 2024 at 5:09 AM
Resolved November 1, 2024 at 5:08 AM