mirror of
https://github.com/luau-lang/luau.git
synced 2025-05-04 10:33:46 +01:00
Create table-destructuring.md
This commit is contained in:
parent
1b20fcd43c
commit
64cca6e158
1 changed files with 236 additions and 0 deletions
236
rfcs/table-destructuring.md
Normal file
236
rfcs/table-destructuring.md
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
# Table Destructuring
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
A feature present and highly-used in JavaScript, table destructuring allows the developer to extract data from tables and assign them to variables in a clean, shortened manner, thus avoiding the need for excessive index calls and several individual assignments, most of which being expendable.
|
||||||
|
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
As of today, the only way to "dynamically" assign table values is via `unpack`/`select` and variable list assignments. With that being said, these functions cannot be used on dictionaries and limit control over what values are being retrieved.
|
||||||
|
|
||||||
|
With the introduction of destructuring assignments, we'll be able to substantially reduce redundant variables, index calls, and bloat in our code. Instead, using a clean syntax that allows the intuitive selection and assignment of values from arrays and dictionaries.
|
||||||
|
|
||||||
|
Destructuring allows for shortened code with increased flexibility. The expected outcome__s__ are endless.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- Example using HTTP Service
|
||||||
|
-- Based on example from https://developer.roblox.com/en-us/api-reference/class/HttpService
|
||||||
|
|
||||||
|
local response = HttpSevice:GetAsync("http://api.open-notify.org/astros.json")
|
||||||
|
local data = HttpService:JSONDecode(response)
|
||||||
|
|
||||||
|
local { message, number, people } = data
|
||||||
|
|
||||||
|
if message == "success" then
|
||||||
|
print("There are currently", data.number, "astronauts in space:")
|
||||||
|
for i, { name, craft } in people do
|
||||||
|
print(i .. ": " .. name .. " is on " .. craft)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- Example using Fusion
|
||||||
|
|
||||||
|
local { New, Children } = Fusion
|
||||||
|
|
||||||
|
return New "ScreenGui" {
|
||||||
|
-- ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- Example using a RemoteFunction callback
|
||||||
|
|
||||||
|
RemoteFunction.InvokeServer = function(player, { target, damage })
|
||||||
|
print("Dealt " .. damage .. " to " .. target.Name)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
```lua
|
||||||
|
-- Current
|
||||||
|
local foo = {1, 2, 3}
|
||||||
|
|
||||||
|
local one, two, three = unpack(foo) -- 1, 2, 3
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local foo = {1, 2, 3}
|
||||||
|
|
||||||
|
local {one, two, three} = foo -- 1, 2, 3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Assignments for Dictionaries
|
||||||
|
```lua
|
||||||
|
-- Current
|
||||||
|
local foo = {
|
||||||
|
red = "good";
|
||||||
|
green = "better";
|
||||||
|
blue = "best";
|
||||||
|
}
|
||||||
|
|
||||||
|
local red, green, blue = foo.red, foo.green, foo.blue
|
||||||
|
print(red) -- good
|
||||||
|
print(green) -- better
|
||||||
|
print(blue) -- best
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local foo = {
|
||||||
|
red = "good";
|
||||||
|
green = "better";
|
||||||
|
blue = "best";
|
||||||
|
}
|
||||||
|
|
||||||
|
local {red, green, blue} = foo
|
||||||
|
print(red) -- good
|
||||||
|
print(green) -- better
|
||||||
|
print(blue) -- best
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Assignments for Function Returns
|
||||||
|
```lua
|
||||||
|
-- Current
|
||||||
|
local function f()
|
||||||
|
return {
|
||||||
|
name = "John";
|
||||||
|
age = 25;
|
||||||
|
gender = "male";
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = f()
|
||||||
|
local name, age, gender = data.name, data.age, data.gender
|
||||||
|
|
||||||
|
print(name) -- John
|
||||||
|
print(age) -- 25
|
||||||
|
print(gender) -- male
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local function f()
|
||||||
|
return {
|
||||||
|
name = "John";
|
||||||
|
age = 25;
|
||||||
|
gender = "male";
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local {name, age, gender} = f()
|
||||||
|
print(name) -- John
|
||||||
|
print(age) -- 25
|
||||||
|
print(gender) -- male
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Assignments for UserData & Vectors
|
||||||
|
```lua
|
||||||
|
-- Current
|
||||||
|
local Part = workspace.Part
|
||||||
|
local Position = Part.CFrame.Position
|
||||||
|
local X, Y, Z = Position.X, Position.Y, Position.Z
|
||||||
|
|
||||||
|
print(X, Y, Z) -- 0, 0, 0
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local Part = workspace.Part
|
||||||
|
local {Position} = Part.CFrame
|
||||||
|
local {X, Y, Z} = Position
|
||||||
|
|
||||||
|
print(X, Y, Z) -- 0, 0, 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variable Assignments for Indexing Children (???)
|
||||||
|
```lua
|
||||||
|
-- Current
|
||||||
|
local Baseplate = workspace.Baseplate
|
||||||
|
print(Baseplate) -- Baseplate
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local {Baseplate} = workspace
|
||||||
|
print(Baseplate) -- Baseplate
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Destructuring Function Parameters
|
||||||
|
```lua
|
||||||
|
-- Before
|
||||||
|
local function f(data)
|
||||||
|
local name = data.name
|
||||||
|
local age = data.age
|
||||||
|
local gender = data.gender
|
||||||
|
|
||||||
|
print(name, age, gender) -- John, 25, male
|
||||||
|
end
|
||||||
|
|
||||||
|
f({
|
||||||
|
name = "John";
|
||||||
|
age = 25;
|
||||||
|
gender = "male";
|
||||||
|
})
|
||||||
|
```
|
||||||
|
```lua
|
||||||
|
-- New
|
||||||
|
local function f({ name, age, gender })
|
||||||
|
print(name, age, gender) -- John, 25, male
|
||||||
|
end
|
||||||
|
|
||||||
|
f({
|
||||||
|
name = "John";
|
||||||
|
age = 25;
|
||||||
|
gender = "male";
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
```lua
|
||||||
|
local foo = {
|
||||||
|
["fizz-buzz"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
local { fizzbuzz = "fizz-buzz" } = foo
|
||||||
|
print(fizzbuzz) -- fizz-buzz
|
||||||
|
```
|
||||||
|
|
||||||
|
### More Complex Example
|
||||||
|
This example is a direct port of the JavaScript example I gave on issue #617.
|
||||||
|
```lua
|
||||||
|
local obj = {
|
||||||
|
name = "John";
|
||||||
|
records = {
|
||||||
|
{
|
||||||
|
date = "7/29/2022";
|
||||||
|
text = "Hello World!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local {
|
||||||
|
name,
|
||||||
|
records = {
|
||||||
|
{ text }
|
||||||
|
}
|
||||||
|
} = obj
|
||||||
|
|
||||||
|
print(name .. " says " .. text) -- John says Hello World!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Drawbacks
|
||||||
|
|
||||||
|
From my perspective, this would be a rather large addition to the language. *Some* of the drawbacks are listed below:
|
||||||
|
* Increased compiler complexity
|
||||||
|
* Considered language bloat
|
||||||
|
* New, unknown syntax
|
||||||
|
* Not necessarily friendly to new programmers
|
||||||
|
|
||||||
|
With that being said, these drawbacks are all subjective, and likely won't matter to people who choose not to use destructuring in their code.
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
The only other alternatives are `unpack`/`select`. If this weren't implemented, it would just lead to longer code.
|
Loading…
Add table
Reference in a new issue