You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Expand description of accesses and give a "dictionary storage" example
* Make the name of the `newValue` parameter configurable
Be consistent with set/willSet/didSet in making the parameter name
optional and overridable.
* A few clarifications regarding init accessor signatures
* Clarify the rules for definite initialization
Expand the examples and show the case where virtual and stored-property
initialization collide.
---------
Co-authored-by: Holly Borla <[email protected]>
Copy file name to clipboardExpand all lines: proposals/NNNN-init-accessors.md
+60-19Lines changed: 60 additions & 19 deletions
Original file line number
Diff line number
Diff line change
@@ -75,7 +75,42 @@ struct Angle {
75
75
}
76
76
```
77
77
78
-
The signature of an `init` accessor specifies the property's access dependencies and the set of stored properties that are initialized by the accessor. Access dependencies must be initialized before the computed property's `init` accessor is invoked, and the `init` accessor must initialize the specified stored properties on all control flow paths.
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`.
79
+
80
+
Access dependencies allow a computed property to be initialized by placing its contents into another stored property:
81
+
82
+
```swift
83
+
structProposalViaDictionary {
84
+
privatevar dictionary: [String: String] = [:]
85
+
86
+
var title: String {
87
+
init(newValue, accesses: dictionary) {
88
+
dictionary["title"] = newValue
89
+
}
90
+
91
+
get { dictionary["title"]! }
92
+
set { dictionary["title"] = newValue }
93
+
}
94
+
95
+
var text: String {
96
+
init(newValue, accesses: dictionary) {
97
+
dictionary["text"] = newValue
98
+
}
99
+
100
+
get { dictionary["text"]! }
101
+
set { dictionary["text"] = newValue }
102
+
}
103
+
104
+
init(title: String, text: String) {
105
+
self.title= title // calls init accessor to insert title into the dictionary
106
+
self.text= text // calls init accessor to insert text into the dictionary
107
+
108
+
// it is an error to omit either initialization above
109
+
}
110
+
}
111
+
```
112
+
113
+
Both `init` accessors document that they access `dictionary`, which allows them to insert the new values into the dictionary with the appropriate key as part of initialization. This allows one to fully abstract away the storage mechanism used in the type.
79
114
80
115
With this proposal, property wrappers have no bespoke definite initialization support. Instead, the desugaring includes an `init` accessor for wrapped properties. The property wrapper code in the Motivation section will desugar to the following code:
81
116
@@ -116,16 +151,17 @@ This proposal adds new syntax for `init` accessor blocks, which can be written i
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.
176
+
139
177
### `init` accessor signatures
140
178
141
-
`init` accessor declarations can optionally specify a signature. An `init` accessor signature is composed of the `newValue` parameter, 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:`label:
179
+
`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:
142
180
143
181
```swift
144
182
structS {
@@ -158,21 +196,21 @@ struct S {
158
196
}
159
197
```
160
198
161
-
If the accessor only uses `newValue`, the signature is not required.
199
+
If the accessor uses the default parameter name `newValue` and neither initializes nor accesses any stored property, the signature is not required.
162
200
163
-
Init accessors can subsume the initialization of a set of stored properties. Subsumed stored properties are specified through the `initializes:` clause of the accessor signature. The body of an `init` accessor is required to initialize the subsumed stored properties on all paths.
201
+
Init accessors can subsume the initialization of a set of stored properties. Subsumed stored properties are specified through the `initializes:` clause of the accessor signature. The body of an `init` accessor is required to initialize the subsumed stored properties on all control flow paths.
164
202
165
-
Init accessors can also require a set of stored properties to already be initialized when the body is evaluated, which are specified through the `accesses:` cause of the signature. These stored properties can be accessed in the accessor body; no other properties or methods on `self` are available inside the accessor body.
203
+
Init accessors can also require a set of stored properties to already be initialized when the body is evaluated, which are specified through the `accesses:` cause of the signature. These stored properties can be accessed in the accessor body; no other properties or methods on `self` are available inside the accessor body, nor is `self` available as a whole object (i.e., to call methods on it).
166
204
167
205
### Definite initialization of properties on `self`
168
206
169
-
The semantics of an assignment inside of a type's initializer depend on whether or not all of `self` is initialized on all paths at the point of assignment. Before `self` is initialized, assignment to a wrapped property is re-written to initialization of the backing property wrapper storage. After `self` is initialized, assignment to a wrapped property is re-written to a call to the wrapped property's setter. For computed properties with `init`accessors, assignment is re-written to an `init` accessor call before`self`is initialized, and assignment is re-written to a setter call after `self` is initialized.
207
+
The semantics of an assignment inside of a type's initializer depend on whether or not all of `self` is initialized on all paths at the point of assignment. Before all of `self` is initialized, assignment to a computed property with an `init`accessor is re-written to an `init` accessor call; after`self`has been initialized, assignment to a computed property is re-written to a setter call.
170
208
171
209
With this proposal, all of `self` is initialized if:
172
-
* All stored properties are initialized on all paths.
210
+
* All stored properties are initialized on all paths, and
173
211
* All computed properties with `init` accessors are virtually initialized on all paths.
174
212
175
-
An assignment to a computed property with an `init` accessor before all of `self` is initialized covers the computed property and all stored properties specified in the`initializes` clause:
213
+
An assignment to a computed property with an `init` accessor before all of `self` is initialized will virtually initialize the computed property and initialize all of the stored properties specified in its`initializes` clause:
176
214
177
215
```swift
178
216
structS {
@@ -183,28 +221,31 @@ struct S {
183
221
}
184
222
185
223
init() {
186
-
self.computed=1// initializes 'computed', 'x1', and 'x2'
224
+
self.computed=1// initializes 'computed', 'x1', and 'x2'; 'self' is now fully initialized
187
225
}
188
226
}
189
227
```
190
228
191
-
An assignment to a stored property before all of `self` is initialized covers the initialization of computed properties with `init` accessors that specify that stored property if the other `initializes:` dependencies are already initialized:
229
+
An assignment to a stored property before all of `self` is initialized will initialize that stored property. When all of the stored properties listed in the `initializes:` clause of a computed property with an `init` accessor have been initialized, that computed property is virtually initialized:
192
230
193
231
```swift
194
232
structS {
195
233
var x1: Int
196
234
var x2: Int
235
+
var x3: Int
197
236
var computed: Int {
198
237
init(newValue, initializes: x1, x2) { ... }
199
238
}
200
239
201
240
init() {
202
-
self.computed=1// initializes 'computed', 'x1', and 'x2'
241
+
self.x1=1// initializes 'x1'; neither 'x2' or 'computed' is initialized
242
+
self.x2=1// initializes 'x2' and 'computed'
243
+
self.x3=1// initializes 'x3'; 'self' is now fully initialized
203
244
}
204
245
}
205
246
```
206
247
207
-
A stored property is considered initialized if it is assigned a value directly, or if a computed property that subsumes its initialization is assigned a value directly:
248
+
An assignment to a computed property where at least one of the stored properties listed in `initializes:` is initialized, but `self` is not initialized, is an error. This prevents double-initialization of the underlying stored properties:
208
249
209
250
```swift
210
251
structS {
@@ -220,7 +261,7 @@ struct S {
220
261
221
262
init(x: Int, y: Int) {
222
263
self.x= x // Only initializes 'x'
223
-
self.y=y//Initializes 'y' and 'point'
264
+
self.point=(x, y)//error: neither the `init` accessor nor the setter can be called here
0 commit comments