Skip to content

Commit 064ce22

Browse files
authored
Add support for readonly members in structs
1 parent 1731e15 commit 064ce22

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

standard/classes.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,7 @@ ref_method_modifier
20942094
| 'override'
20952095
| 'abstract'
20962096
| 'extern'
2097+
| 'readonly' // direct struct members only
20972098
| unsafe_modifier // unsafe code support
20982099
;
20992100
@@ -2132,7 +2133,7 @@ Grammar notes:
21322133

21332134
> *Note*: The overlapping of, and priority between, alternatives here is solely for descriptive convenience; the grammar rules could be elaborated to remove the overlap. ANTLR, and other grammar systems, adopt the same convenience and so *method_body* has the specified semantics automatically. *end note*
21342135
2135-
A *method_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)), `extern` ([§15.6.8](classes.md#1568-external-methods)) and `async` ([§15.15](classes.md#1515-async-functions)) modifiers.
2136+
A *method_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)), `extern` ([§15.6.8](classes.md#1568-external-methods)) and `async` ([§15.15](classes.md#1515-async-functions)). Additionally a *method_declaration* that is contained directly by a *struct_declaration* may include the `readonly` modifier (§cands-diffs-methods).
21362137

21372138
A declaration has a valid combination of modifiers if all of the following are true:
21382139

@@ -3281,6 +3282,7 @@ property_modifier
32813282
| 'override'
32823283
| 'abstract'
32833284
| 'extern'
3285+
| 'readonly' // direct struct members only
32843286
| unsafe_modifier // unsafe code support
32853287
;
32863288
@@ -3301,7 +3303,7 @@ ref_property_body
33013303
33023304
*unsafe_modifier* ([§23.2](unsafe-code.md#232-unsafe-contexts)) is only available in unsafe code ([§23](unsafe-code.md#23-unsafe-code)).
33033305

3304-
There are two kinds of *property_declaration*:
3306+
A *property_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.7.2](classes.md#1572-static-and-instance-properties)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.7.6](classes.md#1576-virtual-sealed-override-and-abstract-accessors)) and `extern` ([§15.6.8](classes.md#1568-external-methods)). Additionally a *property_declaration* that is contained directly by a *struct_declaration* may include the `readonly` modifier (§16.4.11).
33053307

33063308
- The first declares a non-ref-valued property. Its value has type *type*. This kind of property may be readable and/or writeable.
33073309
- The second declares a ref-valued property. Its value is a *variable_reference* ([§9.5](variables.md#95-variable-references)), that may be `readonly`, to a variable of type *type*. This kind of property is only readable.
@@ -3366,6 +3368,7 @@ accessor_modifier
33663368
| 'internal' 'protected'
33673369
| 'protected' 'private'
33683370
| 'private' 'protected'
3371+
| 'readonly' // direct struct members only
33693372
;
33703373
33713374
accessor_body
@@ -3392,6 +3395,7 @@ For a ref-valued property the *ref_get_accessor_declaration* consists optional a
33923395
The use of *accessor_modifier*s is governed by the following restrictions:
33933396

33943397
- An *accessor_modifier* shall not be used in an interface or in an explicit interface member implementation.
3398+
- The *accessor_modifier* `readonly` is permitted only in a *property_declaration* or *indexer_declaration* that is contained directly by a *struct_declaration* (§16.4.11, §cands-diffs-indexers).
33953399
- For a property or indexer that has no `override` modifier, an *accessor_modifier* is permitted only if the property or indexer has both a get and set accessor, and then is permitted only on one of those accessors.
33963400
- For a property or indexer that includes an `override` modifier, an accessor shall match the *accessor_modifier*, if any, of the accessor being overridden.
33973401
- The *accessor_modifier* shall declare an accessibility that is strictly more restrictive than the declared accessibility of the property or indexer itself. To be precise:
@@ -4024,6 +4028,7 @@ event_modifier
40244028
| 'override'
40254029
| 'abstract'
40264030
| 'extern'
4031+
| 'readonly' // direct struct members only
40274032
| unsafe_modifier // unsafe code support
40284033
;
40294034
@@ -4043,7 +4048,7 @@ remove_accessor_declaration
40434048
40444049
*unsafe_modifier* ([§23.2](unsafe-code.md#232-unsafe-contexts)) is only available in unsafe code ([§23](unsafe-code.md#23-unsafe-code)).
40454050

4046-
An *event_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods), [§15.8.4](classes.md#1584-static-and-instance-events)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers.
4051+
An *event_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `static` ([§15.6.3](classes.md#1563-static-and-instance-methods), [§15.8.4](classes.md#1584-static-and-instance-events)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `override` ([§15.6.5](classes.md#1565-override-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods), [§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)) and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers. Additionally an *event_declaration* that is contained directly by a *struct_declaration* may include the `readonly` modifier (§cands-diffs-methods).
40474052

40484053
Event declarations are subject to the same rules as method declarations ([§15.6](classes.md#156-methods)) with regard to valid combinations of modifiers.
40494054

@@ -4304,6 +4309,7 @@ indexer_modifier
43044309
| 'override'
43054310
| 'abstract'
43064311
| 'extern'
4312+
| 'readonly' // direct struct members only
43074313
| unsafe_modifier // unsafe code support
43084314
;
43094315
@@ -4325,7 +4331,7 @@ ref_indexer_body
43254331
43264332
*unsafe_modifier* ([§23.2](unsafe-code.md#232-unsafe-contexts)) is only available in unsafe code ([§23](unsafe-code.md#23-unsafe-code)).
43274333

4328-
There are two kinds of *indexer_declaration*:
4334+
An *indexer_declaration* may include a set of *attributes* ([§22](attributes.md#22-attributes)) and any one of the permitted kinds of declared accessibility ([§15.3.6](classes.md#1536-access-modifiers)), the `new` ([§15.3.5](classes.md#1535-the-new-modifier)), `virtual` ([§15.6.4](classes.md#1564-virtual-methods)), `override` ([§15.6.5](classes.md#1565-override-methods)), `sealed` ([§15.6.6](classes.md#1566-sealed-methods)), `abstract` ([§15.6.7](classes.md#1567-abstract-methods)) and `extern` ([§15.6.8](classes.md#1568-external-methods)) modifiers. Additionally an *indexer_declaration* that is contained directly by a *struct_declaration* may include the `readonly` modifier (§cands-diffs-methods).
43294335

43304336
- The first declares a non-ref-valued indexer. Its value has type *type*. This kind of indexer may be readable and/or writeable.
43314337
- The second declares a ref-valued indexer. Its value is a *variable_reference* ([§9.5](variables.md#95-variable-references)), that may be `readonly`, to a variable of type *type*. This kind of indexer is only readable.

standard/structs.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ The `readonly` modifier indicates that the *struct_declaration* declares a type
5757
A readonly struct has the following constraints:
5858

5959
- Each of its instance fields shall also be declared `readonly`.
60-
- None of its instance properties shall have a *set_accessor_declaration* ([§15.7.3](classes.md#1573-accessors)).
6160
- It shall not declare any field-like events ([§15.8.2](classes.md#1582-field-like-events)).
6261

6362
When an instance of a readonly struct is passed to a method, its `this` is treated like an input argument/parameter, which disallows write access to any instance fields (except by constructors).
@@ -154,6 +153,7 @@ Structs differ from classes in several important ways:
154153
- Instance field declarations for a struct are not permitted to include variable initializers ([§16.4.8](structs.md#1648-field-initializers)).
155154
- A struct is not permitted to declare a parameterless instance constructor ([§16.4.9](structs.md#1649-constructors)).
156155
- A struct is not permitted to declare a finalizer.
156+
- Event declarations, property declarations, property accessors, indexer declarations, and method declarations are permitted to have the modifier `readonly` while that is not generally permitted for those same member kinds in classes.
157157

158158
### 16.4.2 Value semantics
159159

@@ -402,6 +402,8 @@ As described in [§16.4.5](structs.md#1645-default-values), the default value of
402402
>
403403
> *end example*
404404
405+
A *field_declaration* declared directly inside a *struct_declaration* having the *struct_modifier* `readonly` shall have the *field_modifier* `readonly`.
406+
405407
### 16.4.9 Constructors
406408
407409
Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor, which always returns the value that results from setting all value type fields to their default value and all reference type fields to `null` ([§8.3.3](types.md#833-default-constructors)). A struct can declare instance constructors having parameters.
@@ -496,12 +498,56 @@ Static constructors for structs follow most of the same rules as for classes. Th
496498
497499
> *Note*: The creation of default values ([§16.4.5](structs.md#1645-default-values)) of struct types does not trigger the static constructor. (An example of this is the initial value of elements in an array.) *end note*
498500
499-
### 16.4.11 Automatically implemented properties
501+
### 16.4.11 Properties
502+
503+
A *property_declaration* ([§15.7.1](classes.md#1571-general)) for an instance property in a *struct_declaration* may contain the *property_modifier* `readonly`. However, a static property shall not contain that modifier.
504+
505+
It is a compile-time error to attempt to modify the state of an instance struct variable via a readonly property declared in that struct.
506+
507+
It is a compile-time error for an automatically implemented property having a `readonly` modifier, to also have a `set` accessor.
508+
509+
It is a compile-time error for an automatically implemented property in a `readonly` struct to have a `set` accessor.
510+
511+
An automatically implemented property declared inside a `readonly` struct need not have a `readonly` modifier, as its `get` accessor is implicitly assumed to be readonly.
512+
513+
It is a compile-time error to have a `readonly` modifier on a property itself as well as on either of its `get` and `set` accessors.
514+
515+
It is a compile-time error for a property to have a readonly modifier on all of its accessors.
516+
517+
> *Note*: To correct the error, move the modifier from the accessors to the property itself. *end note*
500518
501519
Automatically implemented properties ([§15.7.4](classes.md#1574-automatically-implemented-properties)) use hidden backing fields, which are only accessible to the property accessors.
502520
503521
> *Note*: This access restriction means that constructors in structs containing automatically implemented properties often need an explicit constructor initializer where they would not otherwise need one, to satisfy the requirement of all fields being definitely assigned before any function member is invoked or the constructor returns. *end note*
504522
523+
### §cands-diffs-methods Methods
524+
525+
A *method_declaration* ([§15.6.1](classes.md#1561-general)) for an instance method in a *struct_declaration* may contain the *method_modifier* `readonly`. However, a static method shall not contain that modifier.
526+
527+
It is a compile-time error to attempt to modify the state of an instance struct variable via a readonly method declared in that struct.
528+
529+
Although a readonly method may call a sibling, non-readonly method, or property or indexer get accessor, doing so results in the creation of an implicit copy of `this` as a defensive measure.
530+
531+
A readonly method may call a sibling property or indexer set accessor that is readonly. If a sibling member’s accessor is not explicitly or implicitly readonly, a compile-error occurs.
532+
533+
All *method_declaration*s of a partial method shall have a `readonly` modifier, or none of them shall have it.
534+
535+
### §cands-diffs-indexers Indexers
536+
537+
An *indexer_declaration* ([§15.9](classes.md#159-indexers)) for an instance indexer in a *struct_declaration* may contain the *indexer_modifier* `readonly`.
538+
539+
It is a compile-time error to attempt to modify the state of an instance struct variable via a readonly indexer declared in that struct.
540+
541+
It is a compile-time error to have a `readonly` modifier on an indexer itself as well as on either of its `get` or `set` accessors.
542+
543+
It is a compile-time error for an indexer to have a readonly modifier on all of its accessors.
544+
545+
> *Note*: To correct the error, move the modifier from the accessors to the indexer itself. *end note*
546+
547+
### §cands-diffs-events Events
548+
549+
An *event_declaration* ([§15.8.1](classes.md#1581-general)) for an instance, non-field-like event in a *struct_declaration* may contain the *event_modifier* `readonly`. However, a static event shall not contain that modifier.
550+
505551
### 16.4.12 Safe context constraint
506552
507553
#### 16.4.12.1 General

0 commit comments

Comments
 (0)