Skip to content

Commit fa53eae

Browse files
RexJaeschkeBillWagner
authored andcommitted
reorg record-related text
1 parent a759c94 commit fa53eae

1 file changed

Lines changed: 66 additions & 25 deletions

File tree

standard/structs.md

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,16 @@ record_struct_body
3838
;
3939
```
4040

41-
A *struct_declaration* is for either a ***non-record struct*** or a ***record struct***.
41+
There are two kinds of struct: ***non-record struct***, as declared by *non_record_struct_declaration*, and ***record struct***, as declared by *record_struct_declaration*. A non-record struct is the kind of struct that C# has supported since the language’s inception. Record structs were added much later and are discussed in §record-structs. The differences between the two kinds are discussed in §record-struct-diffs.
4242

4343
A *non_record_struct_declaration* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), followed by an optional set of *struct_modifier*s ([§16.2.2](structs.md#1622-struct-modifiers)), followed by an optional `ref` modifier ([§16.2.3](structs.md#1623-ref-modifier)), followed by an optional partial modifier ([§15.2.7](classes.md#1527-partial-type-declarations)), followed by the keyword `struct` and an *identifier* that names the struct, followed by an optional *type_parameter_list* specification ([§15.2.3](classes.md#1523-type-parameters)), followed by an optional *struct_interfaces* specification ([§16.2.5](structs.md#1625-struct-interfaces)), followed by an optional *type_parameter_constraints-clauses* specification ([§15.2.5](classes.md#1525-type-parameter-constraints)), followed by a *struct_body* ([§16.2.6](structs.md#1626-struct-body)), optionally followed by a semicolon.
4444

45-
A *record_struct_declaration* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), followed by an optional set of *struct_modifier*s ([§16.2.2](structs.md#1622-struct-modifiers)), followed by an optional partial modifier ([§15.2.7](classes.md#1527-partial-type-declarations)), followed by the keyword `record`, followed by the keyword `struct` and an *identifier* that names the struct, followed by an optional *type_parameter_list* specification ([§15.2.3](classes.md#1523-type-parameters)), followed by an optional *delimited_parameter_list* specification ([§15.2.1](classes.md#1521-general)), followed by an optional *struct_interfaces* specification ([§16.2.5](structs.md#1625-struct-interfaces)), followed by an optional *type_parameter_constraints-clauses* specification ([§15.2.5](classes.md#1525-type-parameter-constraints)), followed by a *record_struct_body*.
46-
4745
A *struct_declaration* shall not supply *type_parameter_constraints_clause*s unless it also supplies a *type_parameter_list*.
4846

4947
A *struct_declaration* that supplies a *type_parameter_list* is a generic struct declaration. Additionally, any struct nested inside a generic class declaration or a generic struct declaration is itself a generic struct declaration, since type arguments for the containing type shall be supplied to create a constructed type ([§8.4](types.md#84-constructed-types)).
5048

5149
A *non_record_struct_declaration* that includes a `ref` modifier shall not have a *struct_interfaces* part.
5250

53-
A *record_struct_declaration* having a *delimited_parameter_list* declares a ***positional record struct***.
54-
55-
At most only one *record_struct_declaration* containing `partial` may provide a *delimited_parameter_list*.
56-
57-
The parameters in *delimited_parameter_list* shall not have `ref`, `out` or `this` modifiers; however, `in` and `params` modifiers are permitted.
58-
For a *record_struct_declaration*, the *record_struct_body*s `{}`, `{};`, and `;` are equivalent. They all indicate that the only members are those synthesized by the compiler (§synth-members).
59-
6051
### 16.2.2 Struct modifiers
6152

6253
A *struct_declaration* may optionally include a sequence of *struct_modifier*s:
@@ -145,7 +136,7 @@ struct_body
145136

146137
### 16.3.1 General
147138

148-
The members of a struct consist of the members introduced by its *struct_member_declaration*s and the members inherited from the type `System.ValueType`. For a record struct, the member set also includes the synthesized members generated by the compiler (§synth-members).
139+
The members of a struct consist of the members introduced by its *struct_member_declaration*s and the members inherited from the type `System.ValueType`.
149140

150141
```ANTLR
151142
struct_member_declaration
@@ -169,10 +160,6 @@ struct_member_declaration
169160
170161
Except for the differences noted in [§16.4](structs.md#164-class-and-struct-differences), the descriptions of class members provided in [§15.3](classes.md#153-class-members) through [§15.12](classes.md#1512-static-constructors) apply to struct members as well.
171162

172-
It is an error for a member of a record struct to be named `Clone`.
173-
174-
It is an error for an instance field of a record struct to have an unsafe type.
175-
176163
### 16.3.2 Readonly members
177164

178165
An instance member definition or accessor of an instance property, indexer, or event that includes the `readonly` modifier has the following restrictions:
@@ -213,15 +200,58 @@ An instance member definition or accessor of an instance property, indexer, or e
213200
>
214201
> The `readonly` method `AddMessage` can change the state of a message list. The `InitializeMessages` member can clear and re-initialize the list of messages. In the case of `AddMessage`, the `readonly` modifier is valid. In the case of `InitializeMessages`, adding the `readonly` modifier is invalid. *end example*
215202
216-
## §synth-members Synthesized record struct members
203+
## §record-structs Record structs
204+
205+
### §record-structs-general General
206+
207+
A record struct is a specialized value type that is optimized for storing data rather than behavior. It provides built-in functionality that would normally require significantboilerplatecode in a non-record struct, such as value-based equality and easy immutability.
208+
209+
```ANTLR
210+
record_struct_declaration
211+
: attributes? struct_modifier* 'partial'? 'record' 'struct'
212+
identifier type_parameter_list? delimited_parameter_list? struct_interfaces?
213+
type_parameter_constraints_clause* record_struct_body
214+
;
215+
```
216+
217+
A *record_struct_declaration* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), followed by an optional set of *struct_modifier*s ([§16.2.2](structs.md#1622-struct-modifiers)), followed by an optional partial modifier ([§15.2.7](classes.md#1527-partial-type-declarations)), followed by the keyword `record`, followed by the keyword `struct` and an *identifier* that names the struct, followed by an optional *type_parameter_list* specification ([§15.2.3](classes.md#1523-type-parameters)), followed by an optional *delimited_parameter_list* specification ([§15.6.2.1](standard/classes.md#15621-general)), followed by an optional *struct_interfaces* specification ([§16.2.5](structs.md#1625-struct-interfaces)), followed by an optional *type_parameter_constraints-clauses* specification ([§15.2.5](classes.md#1525-type-parameter-constraints)), followed by a *record_struct_body*.
218+
219+
A *record_struct_declaration* having a *delimited_parameter_list* declares a ***positional record struct***.
220+
221+
At most only one *record_struct_declaration* containing `partial` may provide a *delimited_parameter_list*.
222+
223+
The parameters in *delimited_parameter_list* shall not have `ref`, `out` or `this` modifiers; however, `in` and `params` modifiers are permitted.
217224

218-
### §synth-members-general General
225+
### §record-structs-members Struct members
226+
227+
For a record struct, as well as those members identified by [§16.3](structs.md#16.3-struct-members), the member set includes the synthesized members generated by the compiler (§synth-members).
228+
229+
It is an error for a member of a record struct to be named `Clone`.
230+
231+
It is an error for an instance field of a record struct to have an unsafe type.
232+
233+
### §record-structs-body Record struct body
234+
235+
The *record_struct_body* of a record struct defines the members of that struct.
236+
237+
```ANTLR
238+
record_struct_body
239+
: struct_body ';'?
240+
| ';'
241+
;
242+
```
243+
244+
For a *record_struct_declaration*, the *record_struct_body*s `{}`, `{};`, and `;` are equivalent. They all indicate that the only members are those synthesized by the compiler (§synth-members).
245+
246+
### §synth-members Synthesized record struct members
247+
248+
#### §synth-members-general General
219249

220250
In the case of a record struct, members are synthesized unless a member with a “matching” signature is declared in the *record_struct_body* or an accessible concrete non-virtual member with a “matching” signature is inherited. Two members are considered matching if they have the same signature or would be considered “hiding” in an inheritance scenario. (See Signatures and overloading [§7.6](basic-concepts.md#76-signatures-and-overloading).)
221251

222252
The synthesized members are described in the following subclauses.
223253

224-
### §rec-struct-equalmem Equality members
254+
#### §rec-struct-equalmem Equality members
225255

226256
The synthesized equality members are similar to those for a record class ([§15.16.2](classes.md#15162-equality-members)), except for the lack of `EqualityContract`, null checks, or inheritance.
227257

@@ -301,7 +331,7 @@ The synthesized override of `GetHashCode()` shall return an `int` result of comb
301331
>
302332
> *end example*
303333
304-
### §rec-struct-prtmem Printing members
334+
#### §rec-struct-prtmem Printing members
305335
306336
A record struct includes a synthesized method equivalent to the following:
307337
@@ -388,15 +418,15 @@ This method performs the following tasks:
388418
>
389419
> *end example*
390420
391-
### §rec-struct-pos-mem Positional record struct members
421+
#### §rec-struct-pos-mem Positional record struct members
392422
393-
#### §rec-struct-pos-mem-gen General
423+
##### §rec-struct-pos-mem-gen General
394424
395425
As well as providing the members described in the preceding subclauses, positional record structs ([§16.2.1](structs.md#1621-general)) synthesize additional members with the same conditions as the other members, as described in the following subclauses.
396426
397-
#### §rec-struct-pos-mem-pricon Primary constructor
427+
##### §rec-struct-pos-mem-pricon Primary constructor
398428
399-
A record struct has a public constructor whose signature corresponds to the value parameters of the type declaration. This is called the primary constructor for the type. It is an error to have a primary constructor and a constructor with the same signature already present in the struct. If the type declaration does not include a *delimited_parameter_list*, no primary constructor is generated.
429+
A record struct with a *delimited_parameter_list* has a public constructor whose signature corresponds to the value parameters of the type declaration. This is called the primary constructor for the type. It is an error to have a primary constructor and a constructor with the same signature already present in the struct. If the type declaration does not include a *delimited_parameter_list*, no primary constructor is generated.
400430
401431
> <!-- Example: {template:"standalone-lib", name:"RecordStructPrimaryConstructor1", expectedErrors:["CS0111","CS8862"]} -->
402432
> ```csharp
@@ -433,7 +463,7 @@ The definite assignment rules for struct instance constructors apply to the prim
433463
> }
434464
> ```
435465
436-
#### §rec-struct-pos-mem-props Properties
466+
##### §rec-struct-pos-mem-props Properties
437467
438468
For each parameter of a *delimited_parameter_list* that has the same name and type as an explicitly declared instance field, the remainder of this subclause does not apply.
439469
@@ -455,13 +485,24 @@ For a record struct:
455485
456486
- Attributes may be applied to the synthesized auto-property and its backing field by using `property:` or `field:` targets for attributes syntactically applied to the corresponding record struct parameter.
457487
458-
#### §rec-struct-pos-mem-decon Deconstruct
488+
##### §rec-struct-pos-mem-decon Deconstruct
459489
460490
A positional record struct with at least one parameter synthesizes a public `void`-returning instance method called `Deconstruct` with an out parameter declaration for each parameter of the primary constructor declaration. Each parameter of `Deconstruct` has the same type as the corresponding parameter of the primary
461491
constructor declaration. The body of the method assigns each parameter of the Deconstruct method to the value from an instance member access to a member of the same name.
462492
If the instance members accessed in the body do not include a property with a non-`readonly` `get` accessor, then the synthesized `Deconstruct` method is `readonly`.
463493
The method can be declared explicitly. It is an error if the explicit declaration does not match the expected signature or accessibility, or is static.
464494
495+
## §record-struct-diffs Record struct and non-record struct differences
496+
497+
A record struct differs from a non-record struct in several important ways:
498+
499+
- It is declared using the keywords `record struct` instead of just `struct`.
500+
- It has a number of members generated for it by the implementation.
501+
- Its declaration may contain a *delimited_parameter_list* having zero or more parameters, which results in the generation of a primary constructor having those parameters. For each parameter, the implementation shall provide field-like storage and a property with get and init accessor. A `Deconstruct` method is also provided.
502+
- Its record struct body may be omitted.
503+
- It shall not have a member called `Clone`.
504+
- It shall not have an instance field with an unsafe type.
505+
465506
## 16.4 Class and struct differences
466507
467508
### 16.4.1 General

0 commit comments

Comments
 (0)