-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Field init shorthand #1682
Merged
Merged
Field init shorthand #1682
Changes from 6 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
a88bfbb
Add named-field-puns RFC draft
ranweiler 46a33d3
Wrap words
ranweiler f8e50c5
Caption example usage in summary
ranweiler bd201d6
Remove non-technical use of the word "type"
ranweiler 96bcd13
Tweak adjective
ranweiler 379e50a
Emphasize precedent and symmetry when assessing macros
ranweiler f9827d1
Fix field names in example
ranweiler 8c307c1
Use "similar" to avoid conflation with senses of "shared"
ranweiler 66b2a82
Add subsections to "Alternatives" section
ranweiler 7cfd7e9
Add subsection for sigil alternative
ranweiler 42f4035
Explicit type punning alternative.
Havvy 673da42
Merge pull request #1 from Havvy/patch-1
ranweiler ec7f3b1
Add subsections to "Detailed design" section
ranweiler 23b9194
Fix EOF newline
ranweiler 7016ba9
Add description of formal grammar change
ranweiler b425e05
Rename feature to "field-init-shorthand"
ranweiler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
- Feature Name: named-field-puns | ||
- Start Date: 2016-07-18 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
When initializing a data structure (struct, enum, union) with named fields, | ||
allow writing `fieldname` as a shorthand for `fieldname: fieldname`. This | ||
allows a compact syntax for initialization, with less duplication. | ||
|
||
Example usage: | ||
|
||
struct SomeStruct { field1: ComplexType, field2: AnotherType } | ||
|
||
impl SomeStruct { | ||
fn new() -> Self { | ||
let field1 = { | ||
// Various initialization code | ||
}; | ||
let field2 = { | ||
// More initialization code | ||
}; | ||
SomeStruct { complexField, anotherField } | ||
} | ||
} | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
When writing initialization code for a data structure, the names of the | ||
structure fields often become the most straightforward names to use for their | ||
initial values as well. At the end of such an initialization function, then, | ||
the initializer will contain many patterns of repeated field names as field | ||
values: `field: field, field2: field2, field3: field3`. | ||
|
||
Such repetition of the field names makes it less ergonomic to separately | ||
declare and initialize individual fields, and makes it tempting to instead | ||
embed complex code directly in the initializer to avoid repetition. | ||
|
||
Rust already allows | ||
[similar syntax for destructuring in pattern matches](https://doc.rust-lang.org/book/patterns.html#destructuring): | ||
a pattern match can use `SomeStruct { field1, field2 } => ...` to match | ||
`field1` and `field2` into values with the same names. This RFC introduces | ||
symmetrical syntax for initializers. | ||
|
||
A family of related structures will often use the same field name for a | ||
semantically-shared value. Combining this new syntax with the existing | ||
pattern-matching syntax allows simple movement of data between fields with a | ||
pattern match: `Struct1 { field1, .. } => Struct2 { field1 }`. | ||
|
||
The proposed syntax also improves structure initializers in closures, such as | ||
might appear in a chain of iterator adapters: `|field1, field2| SomeStruct { | ||
field1, field2 }`. | ||
|
||
This RFC takes inspiration from the Haskell | ||
[NamedFieldPuns extension](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#record-puns), | ||
and from ES6 | ||
[shorthand property names](http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer). | ||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
In the initializer for a `struct` with named fields, a `union` with named | ||
fields, or an enum variant with named fields, accept an identifier `field` as a | ||
shorthand for `field: field`. | ||
|
||
The shorthand initializer `field` always behaves in every possible way like the | ||
longhand initializer `field: field`. This RFC introduces no new behavior or | ||
semantics, only a purely syntactic shorthand. The rest of this section only | ||
provides further examples to explicitly clarify that this new syntax remains | ||
entirely orthogonal to other initializer behavior and semantics. | ||
|
||
If the struct `SomeStruct` has fields `field1` and `field2`, the initializer | ||
`SomeStruct { field1, field2 }` behaves in every way like the initializer | ||
`SomeStruct { field1: field1, field2: field2 }`. | ||
|
||
An initializer may contain any combination of shorthand and full field | ||
initializers: | ||
|
||
let a = SomeStruct { field1, field2: expression, field3 }; | ||
let b = SomeStruct { field1: field1, field2: expression, field3: field3 }; | ||
assert_eq!(a, b); | ||
|
||
An initializer may use shorthand field initializers together with | ||
[update syntax](https://doc.rust-lang.org/book/structs.html#update-syntax): | ||
|
||
let a = SomeStruct { field1, .. someStructInstance }; | ||
let b = SomeStruct { field1: field1, .. someStructInstance }; | ||
assert_eq!(a, b); | ||
|
||
This shorthand initializer syntax does not introduce any new compiler errors | ||
that cannot also occur with the longhand initializer syntax `field: field`. | ||
Existing compiler errors that can occur with the longhand initializer syntax | ||
`field: field` also apply to the shorthand initializer syntax `field`: | ||
|
||
- As with the longhand initializer `field: field`, if the structure has no | ||
field with the specified name `field`, the shorthand initializer `field` | ||
results in a compiler error for attempting to initialize a non-existent | ||
field. | ||
|
||
- As with the longhand initializer `field: field`, repeating a field name | ||
within the same initializer results in a compiler error | ||
([E0062](https://doc.rust-lang.org/error-index.html#E0062)); this occurs with | ||
any combination of shorthand initializers or full `field: expression` | ||
initializers. | ||
|
||
- As with the longhand initializer `field: field`, if the name `field` does not | ||
resolve, the shorthand initializer `field` results in a compiler error for an | ||
unresolved name ([E0425](https://doc.rust-lang.org/error-index.html#E0425)). | ||
|
||
- As with the longhand initializer `field: field`, if the name `field` resolves | ||
to a value with type incompatible with the field `field` in the structure, | ||
the shorthand initializer `field` results in a compiler error for mismatched | ||
types ([E0308](https://doc.rust-lang.org/error-index.html#E0308)). | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
This new syntax could significantly improve readability given clear and local | ||
field-punning variables, but could also be abused to decrease readability if | ||
used with more distant variables. | ||
|
||
As with many syntactic changes, a macro could implement this instead. See the | ||
Alternatives section for discussion of this. | ||
|
||
The shorthand initializer syntax looks similar to positional initialization of | ||
a structure without field names; reinforcing this, the initializer will | ||
commonly list the fields in the same order that the struct declares them. | ||
However, the shorthand initializer syntax differs from the positional | ||
initializer syntax (such as for a tuple struct) in that the positional syntax | ||
uses parentheses instead of braces: `SomeStruct(x, y)` is unambiguously a | ||
positional initializer, while `SomeStruct { x, y }` is unambiguously a | ||
shorthand initializer for the named fields `x` and `y`. | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
In addition to this syntax, initializers could support omitting the field names | ||
entirely, with syntax like `SomeStruct { .. }`, which would implicitly | ||
initialize omitted fields from identically named variables. However, that would | ||
introduce far too much magic into initializers, and the context-dependence | ||
seems likely to result in less readable, less obvious code. | ||
|
||
A macro wrapped around the initializer could implement this syntax, without | ||
changing the language; for instance, `pun! { SomeStruct { field1, field2 } }` | ||
could expand to `SomeStruct { field1: field1, field2: field2 }`. However, this | ||
change exists to make structure construction shorter and more expressive; | ||
having to use a macro would negate some of the benefit of doing so, | ||
particularly in places where brevity improves readability, such as in a closure | ||
in the middle of a larger expression. There is also precedent for | ||
language-level support. Pattern matching already allows using field names as | ||
the _destination_ for the field values via destructuring. This change adds a | ||
symmetrical mechanism for construction which uses existing names as _sources_. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this line be
SomeStruct { field1, field2 }
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sure should, thanks!