Can Destructured Variables Be Scoped In ColdFusion?

October 11, 2022    

Destructuring is a convenient way to assign the values from complex objects like arrays & structs into distinct variables. That's all well & good, but all examples I've seen don't bother with variable scoping. Proper scoping is important for explicitness and to better understand where your variables are coming from. Without proper scoping, you may be pulling a variable from an unexpected location.

All examples that follow were written and executed on ColdFusion 2021, Update 4 using cffiddle.org.

Destructuring Examples

In case you're not aware of how destructuring is done in ColdFusion, I'll start off with some basic examples.

First, we'll start off with an array:

items = [ "apple", "banana" ];
[ item1, item2 ] = items;
writeOutput( item1 ); // "apple"
writeOutput( item2 ); // "banana"

Now, a struct:

items = {
apple: "an apple is a fruit",
asparagus: "asparagus is a vegetable",
chocolate: "chocolate is a sweet"
};

( { apple, asparagus } = items );
writeOutput( apple ); // "an apple is a fruit"
writeOutput( asparagus ); // "asparagus is a vegetable"

Notice that we only asked to destructure two of the three keys in this example. That is perfectly fine to do.

Can we scope a destructured variable?

Before we dive in to scoping a destructured variable, let's NOT scope the variables to establish a baseline understanding of how this works.

function destructuringTest() {
local.items = {
apple: "an apple is a fruit",
asparagus: "asparagus is a vegetable",
chocolate: "chocolate is a sweet"
};

( { apple, asparagus } = local.items );

writeDump( var: local, label: "local scope" );
writeDump( var: variables, label: "variables scope" );
}

destructuringTest();

Here are the results from CFFiddle (test code):

Results of destructuring showing that the destructured variables went to the variables scope

Since we didn't specify a scope, the variables apple and asparagus go to the variables scope by default. This is what I expected to happen, because that's what ColdFusion does if you don't provide a variable scope.

Now for the fun part. We throw all caution to the wind and scope the destructured variables...

function destructuringTest() {
local.items = {
apple: "an apple is a fruit",
asparagus: "asparagus is a vegetable",
chocolate: "chocolate is a sweet"
};

( { local.apple, local.asparagus } = local.items );

writeDump( local );
writeDump( variables );
}

destructuringTest();

Again, the results from CFFiddle (test code):

Results of destructuring showing that the destructured variables went... somewhere

It doesn't look like the variables went anywhere. They're not in the local scope, and they're not in the variables scope either. I also checked the server, application (doesn't exist in CFFiddle), request, form, and URL scopes too, but came up empty.

But why?

Let's recall how destructuring works. When we destructure a struct, the left-hand side of the statement will extract values for keys that match from the right-hand side of the statement - even for nested data. In our struct examples, the key from the source struct was "apple", but we were trying to to destructure a key "local.apple". That key didn't exist, so the request to destructure it was ignored. I would have gotten the exact same result had I tried to destructure the key "cake"; it doesn't exist either, so it gets ignored.

A bright spot here is that scoping a destructured variable DOES work for arrays. Here's proof if you are interested.

Conclusion

Scoping a destructured variable only works for arrays. It does not work for structs.

UPDATE: As mentioned by a commenter below, you can actually get variables in the local scope when destructuring a structure; you just can't use the explicit local scope (test code on CFFiddle).

local.items = {
apple: "an apple is a fruit",
asparagus: "asparagus is a vegetable",
chocolate: "chocolate is a sweet"
};

var { apple, asparagus } = local.items;

writeDump( local );
writeDump( variables );