Closed crywink closed 4 months ago
local foo = {
1,
2,
3,
one = "one",
two = "two",
three = "three",
}
local {one, two, three} = foo
Would this be 1, 2, 3
or "one", "two", "three"
? The way it's proposed has ambiguity.
I think this would also have to go through the RFC process, which is more detailed for when the language receives significant changes.
local foo = { 1, 2, 3, one = "one", two = "two", three = "three", } local {one, two, three} = foo
Would this be
1, 2, 3
or"one", "two", "three"
? The way it's proposed has ambiguity.I think this would also have to go through the RFC process, which is more detailed for when the language receives significant changes.
This would be "one", "two", "three"
-- you're indexing one
, two
, and three
.
local foo = {1, 2, 3}
local {one, two, three} = foo
So then, this is nil, nil, nil
? That's not what the comment in your first example says.
Or does the string key take priority, and is the array part of the table a fallback? That's also very confusing.
local foo = {1, 2, 3} local {one, two, three} = foo
So then, this is
nil, nil, nil
? That's not what the comment in your first example says. Or does the string key take priority, and is the array part of the table a fallback? That's also very confusing.
When the table being destructured is an array, the assignment acts the same as unpack
would. I agree it's somewhat confusing, but I think it makes the most sense given the fact that arrays and dictionaries are both encapsulated in curly brackets.
In JavaScript, arrays are wrapped in brackets, while objects (dictionaries) are wrapped in curly brackets. Hopefully this example I wrote gives you a good idea as to how array vs dictionary destructuring works.
const obj = {
name: "John",
records: [
{
date: "7/29/2022",
text: "Hello World!"
}
]
}
let {
name,
records: [
{ text }
]
} = obj;
console.log(name + " says " + text) // John says Hello World!
Since I'm bringing up the JavaScript examples, I'd also like to shine light on the fact that you could also assign new variable names to destructured values. Here's a good example of that using the same object from the previous example:
const obj = {
name: "John",
records: [
{
date: "7/29/2022",
text: "Hello World!"
}
]
}
let {
name: objectName,
records: [
{ text: firstRecordText }
]
} = obj;
console.log(objectName + " says " + firstRecordText) // John says Hello World!
Destructuring can be super powerful when you understand how it works and how it can be used. Let the examples above act as proof to that.
Just an FYI that an issue has already been made for this a while ago, but was closed as it should've been an RFC: https://github.com/Roblox/luau/issues/126#issuecomment-1005007173
If you want this to go any further than the previous one, I would recommend starting an RFC for it instead
I'll just throw a lazy vote of "no", I love lua for being small and I like being able to keep the lua syntax in my head ❤️, and would like luau to stay as close to lua as possible. I am not a maintainer just a happy user
If an RFC were written about this feature, I think it'd be important to explain behavior with mixed tables, and behavior with __index
.
local value = {secret = "key", 1, 2}
local {secret} = value -- Is `secret` `key` or `1`?
If an RFC were written about this feature, I think it'd be important to explain behavior with mixed tables, and behavior with
__index
.local value = {secret = "key", 1, 2} local {secret} = value -- Is `secret` `key` or `1`?
Perhaps for mixed tables, numeric indices are treated as regular keys, so in order to get 1 or 2, you would need to use numbers like this:
local value = {secret = "key", 1, 2}
local {secret} = value -- secret is secret
local {first = 1}
This wouldn't work with the current proposal, but maybe with what crywink suggested here:
Since I'm bringing up the JavaScript examples, I'd also like to shine light on the fact that you could also assign new variable names to destructured values. Here's a good example of that using the same object from the previous example:
It would be cool to have a syntax similar to as follows:
local {folderName = Name, Locked} = folder
-- Locked has no equals sign, so it is taken as Locked = Locked. folderName does, so it takes it from whatever the value is.
-- The value can't be anything other than an identifier or a number representing a numeric index
local {a = 2, b = 1} = {10,12}
print(a,b) -- 12,10
Although, this does bring up the problem with non-string and non-numeric indices and __index
. How would we allow, for example, function indices? Or coroutines, or other tables, or userdata, etc...
Another thing is, for functions, how would typed arguments work?
-- New local function f({ name, age, gender }) print(name, age, gender) -- John, 25, male end f({ name = "John"; age = 25; gender = "male"; })
If I wanted to explicitly set "name" as string, how would I do it? Maybe like this?
local function f({ name: string, age: number, gender: string })
print(name, age, gender) -- John, 25, male
end
Finally, for unwrapping variables, should we allow this behavior to work with assigning existing variables, or only creating new ones? If so, should we allow creation of global variables (defining non-local variables for the first time)? In both cases, this would require the syntax to work without the {}
which may not be possible due to this example of ambiguity:
local a,b
f()
{a,b} = {1,2}
-- Can be confused as:
local a,b
f()({a,b}) = {1,2}
Of course, we can tell that this is a destructuring statement because of the equals sign, but this would require looking ahead which can add complexity to the parser.
We talked about this before in OSS Discord and to make sure that it's preserved. From what I recall, here was the outcome:
local { a, b } = x
will be accepted. It is not clear if this is array-unpacking (a = x[1]
, b = x[2]
) or dictionary-unpacking (a = x.a
, b = x.b
). Misunderstanding this will cause very subtle logic errors that might not be caught by non-strict type checking.local [a, b] = x
also would not work, because []
isn't used for arrays in Luau anyway, but also it causes issues with nesting where local [[a, b], c]
is parsed as a multi-lined string from [[
.local { .a, .b } = x
might work for dictionary-unpacking, since it's more clear what exactly it's doing. It also fits defaults potentially with something like local { .a = 1 } = x
.
Description
A feature present and highly-used in JavaScript, table destructuring lets the developer assign table values to variables natively. I'd like to suggest this same (or functionally similar) functionality be implemented in Luau. Additionally, this feature can be used with special types. (examples below)
Usage
Variable Assignments for Arrays
With the ability to use
unpack
to destructure arrays, the need for this feature can seem negligible. Nevertheless,unpack
cannot be used on dictionaries.Variable Assignments for Dictionaries
Variable Assignments for Function Returns
Variable Assignments for UserData & Vectors
Variable Assignments for Indexing Children (???)
Destructuring Function Parameters
Defining Alternative Identifiers (Questionable?)
In this example,
fizz-buzz
is not a valid identifier. You should be able to instead define an alternative identifier, like so.Conclusion
There are more features that could be added once destructuring is implemented, like defining default function parameters. I overall believe that this, if implemented correctly, would be an extremely helpful QOL feature.