Skip to content

Commit ef2e2c6

Browse files
committed
Update the syntax for init accessor effects based on pitch feedback.
1 parent 72a2cdd commit ef2e2c6

File tree

1 file changed

+42
-28
lines changed

1 file changed

+42
-28
lines changed

proposals/NNNN-init-accessors.md

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ This proposal adds _`init` accessors_ to opt computed properties on types into v
5757
struct Angle {
5858
var degrees: Double
5959
var radians: Double {
60-
init(newValue, initializes: degrees) {
60+
init(newValue) initializes(degrees) {
6161
degrees = newValue * 180 / .pi
6262
}
6363

@@ -75,16 +75,16 @@ struct Angle {
7575
}
7676
```
7777

78-
The signature of an `init` accessor specifies up to two sets of stored properties: the access dependencies (via `accesses`) and the initialized properties (via `initializes`). Access dependencies specify the other stored properties that can be accessed from within the `init` accessor (no other uses of `self` are allowed), and therefore must be initialized before the computed property's `init` accessor is invoked. The `init` accessor must initialize each of the initialized stored properties on all control flow paths. The `radians` property in the example above specifies no access dependencies, but initializes the `degrees` property, so it specifies only `initializes: degrees`.
78+
The signature of an `init` accessor specifies up to two sets of stored properties: the properties that are accessed (via `accesses`) and the properties that are initialized (via `initializes`) by the accessor. `initializes` and `accesses` are side-effects of the `init` accessor. Access effects specify the other stored properties that can be accessed from within the `init` accessor (no other uses of `self` are allowed), and therefore must be initialized before the computed property's `init` accessor is invoked. The `init` accessor must initialize each of the initialized stored properties on all control flow paths. The `radians` property in the example above specifies no access effect, but initializes the `degrees` property, so it specifies only `initializes: degrees`.
7979

80-
Access dependencies allow a computed property to be initialized by placing its contents into another stored property:
80+
Access effects allow a computed property to be initialized by placing its contents into another stored property:
8181

8282
```swift
8383
struct ProposalViaDictionary {
8484
private var dictionary: [String: String] = [:]
8585

8686
var title: String {
87-
init(newValue, accesses: dictionary) {
87+
init(newValue) accesses(dictionary) {
8888
dictionary["title"] = newValue
8989
}
9090

@@ -93,7 +93,7 @@ struct ProposalViaDictionary {
9393
}
9494

9595
var text: String {
96-
init(newValue, accesses: dictionary) {
96+
init(newValue) accesses(dictionary) {
9797
dictionary["text"] = newValue
9898
}
9999

@@ -123,7 +123,7 @@ struct Wrapper<T> {
123123
struct S {
124124
private var _value: Wrapper<Int>
125125
var value: Int {
126-
init(newValue, initializes: _value) {
126+
init(newValue) initializes(_value) {
127127
self._value = Wrapper(wrappedValue: newValue)
128128
}
129129

@@ -149,33 +149,25 @@ This proposal allows macros to model the following property-wrapper-like pattern
149149
This proposal adds new syntax for `init` accessor blocks, which can be written in the accessor list of a computed property. Init accessors add the following production rules to the grammar:
150150

151151
```
152-
init-accessor -> 'init' init-accessor-signature[opt] function-body
152+
init-accessor -> 'init' init-accessor-parameter[opt] init-effect[opt] access-effect[opt] function-body
153153
154-
init-accessor-signature -> '(' init-dependency-clause [opt] ')'
154+
init-accessor-parameter -> '(' identifier ')'
155155
156-
init-dependency-clause -> identifier
157-
init-dependency-clause -> identifier ',' init-dependencies
158-
init-dependency-clause -> init-dependencies
156+
init-effect -> 'initializes' '(' identifier-list ')'
159157
160-
init-dependencies -> initializes-list
161-
init-dependencies -> initializes-list ',' accesses-list
162-
init-dependences -> access-list
163-
164-
initializes-list -> 'initializes' ':' identifier-list
165-
166-
accesses-list -> 'accesses' ':' identifier-list
158+
access-effect -> 'accesses' '(' identifier-list ')'
167159
168160
identifier-list -> identifier
169161
identifier-list -> identifier ',' identifier-list
170162
171163
accessor-block -> init-accessor
172164
```
173165

174-
The `identifier` in an `init-dependency-clause`, if provided, is the name of the parameter that contains the initial value. If not provided, a parameter with the name `newValue` is automatically created.
166+
The `identifier` in an `init-accessor-parameter`, if provided, is the name of the parameter that contains the initial value. If not provided, a parameter with the name `newValue` is automatically created.
175167

176168
### `init` accessor signatures
177169

178-
`init` accessor declarations can optionally specify a signature. An `init` accessor signature is composed of a parameter for the initial value, a list of stored properties that are initialized by this accessor specified with the `initializes:` label, and a list of stored properties that are accessed by this accessor specified with the `accesses:` labe, all of which are optional:
170+
`init` accessor declarations can optionally specify a signature. An `init` accessor signature is composed of a parameter for the initial value, a list of stored properties that are initialized by this accessor specified with the contextual `initializes` keyword, and a list of stored properties that are accessed by this accessor specified with the contextual `accesses` keyword, all of which are optional:
179171

180172
```swift
181173
struct S {
@@ -184,7 +176,7 @@ struct S {
184176
var _x: Int
185177

186178
var x: Int {
187-
init(newValue, initializes: _x, accesses: readMe) {
179+
init(newValue) initializes(_x) accesses(readMe) {
188180
print(readMe)
189181
_x = newValue
190182
}
@@ -216,7 +208,7 @@ struct S {
216208
var x1: Int
217209
var x2: Int
218210
var computed: Int {
219-
init(newValue, initializes: x1, x2) { ... }
211+
init(newValue) initializes(x1, x2) { ... }
220212
}
221213

222214
init() {
@@ -233,7 +225,7 @@ struct S {
233225
var x2: Int
234226
var x3: Int
235227
var computed: Int {
236-
init(newValue, initializes: x1, x2) { ... }
228+
init(newValue) initializes(x1, x2) { ... }
237229
}
238230

239231
init() {
@@ -251,7 +243,7 @@ struct S {
251243
var x: Int
252244
var y: Int
253245
var point: (Int, Int) {
254-
init(newValue, initializes: x, y) {
246+
init(newValue) initializes(x, y) {
255247
(self.x, self.y) = newValue
256248
}
257249
get { (x, y) }
@@ -273,7 +265,7 @@ If a struct does not declare its own initializers, it receives an implicit membe
273265
struct S {
274266
var _x: Int
275267
var x: Int {
276-
init(newValue, initializes: _x) {
268+
init(newValue) initializes(_x) {
277269
_x = newValue
278270
}
279271

@@ -296,13 +288,13 @@ init(x: Int, y: Int) {
296288
}
297289
```
298290

299-
A memberwise initializer cannot be synthesized if a stored property that is an `accesses:` dependency of a computed property is ordered after that computed property in the source code:
291+
A memberwise initializer cannot be synthesized if a stored property that is an `accesses` effect of a computed property is ordered after that computed property in the source code:
300292

301293
```swift
302294
struct S {
303295
var _x: Int
304296
var x: Int {
305-
init(newValue, initializes: _x, reads: y) {
297+
init(newValue) initializes(_x) accesses(y) {
306298
_x = newValue
307299
}
308300

@@ -335,7 +327,29 @@ Note that macro-expanded declarations are ordered after the attached-to declarat
335327

336328
## Implications on adoption
337329

338-
Because `init` accessors are always called from within the defining module, adopting `init` accessors is an ABI-compatible change. Adding an `init` accessor to an existing property also cannot have any source compatibility impact outside of the defining module; the only possible source incompatibilities are on the generated memberwise initializer (if new entries are added), or on the type's `init` implementation (if new initialization dependencies are added).
330+
Because `init` accessors are always called from within the defining module, adopting `init` accessors is an ABI-compatible change. Adding an `init` accessor to an existing property also cannot have any source compatibility impact outside of the defining module; the only possible source incompatibilities are on the generated memberwise initializer (if new entries are added), or on the type's `init` implementation (if new initialization effects are added).
331+
332+
## Alternatives considered
333+
334+
A previous version of this proposal specified init accessor effects in the parameter list using special labels:
335+
336+
```swift
337+
struct S {
338+
var _x: Int
339+
var x: Int {
340+
init(newValue, initializes: _x, accesses: y) {
341+
_x = newValue
342+
}
343+
344+
get { _x }
345+
set { _x = newValue }
346+
}
347+
348+
var y: Int
349+
}
350+
```
351+
352+
This syntax choice is misleading because the effects look like function parameters, while `initializes` behaves more like the output of an init accessor, and `accesses` are not explicitly provided at the call-site. Conceptually, `initializes` and `accesses` are side effects of an `init` accessor, so the proposal was revised to place these modifiers in the effects clause.
339353

340354
## Future directions
341355

0 commit comments

Comments
 (0)