mirror of
https://github.com/luau-lang/rfcs.git
synced 2025-05-04 10:43:48 +01:00
Add syntax-shorthand-field-init.md
This commit is contained in:
parent
85b4d9a9d9
commit
ebfdcee8d8
1 changed files with 157 additions and 0 deletions
157
docs/syntax-shorthand-field-init.md
Normal file
157
docs/syntax-shorthand-field-init.md
Normal file
|
@ -0,0 +1,157 @@
|
|||
# Shorthand field initialization
|
||||
|
||||
## Summary
|
||||
|
||||
This RFC proposes a shorthand syntax for declaring fields in tables, which allows writing
|
||||
`.fieldName` instead of `fieldName = fieldName` when the value of the field is being set to a
|
||||
variable of the same name as the field.
|
||||
|
||||
## Motivation
|
||||
|
||||
It is very common for the variable which you assign as the value of a field in a table to have the
|
||||
same name as said field.
|
||||
|
||||
In these cases, you end up writing the name of the variable at least three times. The following
|
||||
block of code illustrates an example of this.
|
||||
```lua
|
||||
local str = ":)"
|
||||
local tbl = {
|
||||
str = str,
|
||||
}
|
||||
```
|
||||
|
||||
This repetition makes it less ergonomic to declare *variables* which you assign to
|
||||
fields, as opposed to *embedding* the value of those variables directly in the initialization of the
|
||||
field. As an example of this, the above code snippet could be written as the following:
|
||||
```lua
|
||||
local tbl = {
|
||||
str = ":)",
|
||||
}
|
||||
```
|
||||
|
||||
This modification is often not ideal. For example, if the computation of the value of some fields
|
||||
depends on the value of other fields, or if the expression which would be used instead of the
|
||||
variable in the field initialization is too complex. Another example is module exports.
|
||||
|
||||
A module exporting some function `init` *may* look like the following:
|
||||
```lua
|
||||
local function init()
|
||||
-- ...
|
||||
end
|
||||
|
||||
return table.freeze({
|
||||
init = init,
|
||||
})
|
||||
```
|
||||
As you can see, the one field's variable (`init`) has to be written at least three times. Using a
|
||||
different method of exporting variables from modules, you may end up with the following code:
|
||||
```lua
|
||||
local module = {}
|
||||
|
||||
function module.init()
|
||||
end
|
||||
|
||||
return table.freeze(module)
|
||||
```
|
||||
Using this method, the name of the returned table needs to be written (2 + n) times, where n is the
|
||||
number of variables you export. Every exported variable also needs to be written at least one or
|
||||
three times. Potentially three times because you may need to localize exported variables before
|
||||
adding them to the returned table. An example of this would be the following.
|
||||
```lua
|
||||
local module = {}
|
||||
|
||||
export type TypeWhichSomeExportedVariableHas = {
|
||||
str: string,
|
||||
}
|
||||
|
||||
-- localize first so that we can specify the type of `SOME_EXPORTED_VARIABLE`.
|
||||
local SOME_EXPORTED_VARIABLE: TypeWhichSomeExportedVariableHas = {
|
||||
str = ":)",
|
||||
}
|
||||
|
||||
module.SOME_EXPORTED_VARIABLE = SOME_EXPORTED_VARIABLE
|
||||
|
||||
return table.freeze(module)
|
||||
```
|
||||
So, this method may (arguably) be more ergonomic or less ergonomic than the method which first was
|
||||
mentioned. However, using shorthand field initialization syntax instead, it could be written like
|
||||
this:
|
||||
```lua
|
||||
export type TypeWhichSomeExportedVariableHas = {
|
||||
str: string,
|
||||
}
|
||||
|
||||
local SOME_EXPORTED_VARIABLE: TypeWhichSomeExportedVariableHas = {
|
||||
str = ":)",
|
||||
}
|
||||
|
||||
return table.freeze({
|
||||
.init,
|
||||
})
|
||||
```
|
||||
Which (arguably) is better.
|
||||
|
||||
## Design
|
||||
|
||||
### Grammar
|
||||
|
||||
The proposed grammar expands the `field` rule to the following:
|
||||
```
|
||||
field = '[' exp ']' '=' exp | NAME '=' exp | exp | '.' NAME
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
For some module exporting a type, `Phone`, and a function, `init`, which creates a table of type
|
||||
`Phone`, the proposed syntax may be used in the following way:
|
||||
```lua
|
||||
export type Phone = {
|
||||
number: number,
|
||||
owner: string,
|
||||
}
|
||||
|
||||
local function init(number, owner): Phone
|
||||
return {
|
||||
-- NOTE: The following line of code may be written in a number of different, but equivalent
|
||||
-- ways. For example:
|
||||
-- * .number;
|
||||
-- * number = number,
|
||||
-- * number = number;
|
||||
.number,
|
||||
-- NOTE: The following line of code may be written in a number of different, but equivalent
|
||||
-- ways. For example:
|
||||
-- * .owner;
|
||||
-- * .owner (since it's the last element)
|
||||
-- * owner = owner,
|
||||
-- * owner = owner;
|
||||
-- * owner = owner (since it's the last element)
|
||||
.owner,
|
||||
}
|
||||
end
|
||||
|
||||
return table.freeze({
|
||||
-- NOTE: The following line of code may be written in a number of different, but equivalent
|
||||
-- ways. For example:
|
||||
-- * .init;
|
||||
-- * .init (since it's the last element)
|
||||
-- * init = init,
|
||||
-- * init = init;
|
||||
-- * init = init (since it's the last element)
|
||||
.init,
|
||||
})
|
||||
```
|
||||
|
||||
## Drawbacks
|
||||
|
||||
Introducing this shorthand syntax adds a small level of complexity to the language, which
|
||||
potentially is confusing to newcomers. It also occupies syntax which might preferably be used for
|
||||
other features in the future.
|
||||
|
||||
## Alternatives
|
||||
|
||||
The added grammar to the `field` rule needs to have a prefix included, since it otherwise would be
|
||||
indistinguishable from initialization of array-like table fields, but there are alternatives for
|
||||
what that prefix may be.
|
||||
|
||||
Additionally, if records are introduced in the future, this type of syntax could be used for them
|
||||
exclusively, and without a prefix, arguably making code look "cleaner".
|
Loading…
Add table
Reference in a new issue