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
Copy file name to clipboardExpand all lines: proposals/NNNN-non-escapable.md
+28-24Lines changed: 28 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,23 +16,23 @@ This complements the `~Copyable` types added with SE-0390 by introducing another
16
16
17
17
In addition, these types will support lifetime-dependency constraints (being tracked in a separate proposal), that allow them to safely hold pointers referring to data stored in other types.
18
18
19
-
This feature is a key requirement for the proposed `StorageView` type.
19
+
This feature is a key requirement for the proposed `Span` type.
20
20
21
21
**See Also**
22
22
23
23
*[SE-0390: Noncopyable structs and enums](https://github.com/apple/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md)
24
24
*[Language Support for Bufferview](https://forums.swift.org/t/roadmap-language-support-for-bufferview/66211)
25
25
*[Roadmap for improving Swift performance predictability: ARC improvements and ownership control](https://forums.swift.org/t/a-roadmap-for-improving-swift-performance-predictability-arc-improvements-and-ownership-control/54206)
Swift's current notion of an "iterator" has several weaknesses that become apparent when you try to use it in extremely performance-constrained environments.
33
-
These weaknesses arise from the desire to ensure safety while simultaneously allowing iterator values to be arbitrarily copied to support multi-iterator algorithms.
33
+
These weaknesses arise from the desire to ensure safety while simultaneously allowing iterator values to be arbitrarily copied in support of multi-iterator algorithms.
34
34
35
-
For example, the standard library iterator for Array logically creates a copy of the Array when it is constructed; this ensures that changes to the array cannot affect the iteration.
35
+
For example, the standard library iterator for Array logically creates a copy of the Array when it is initialized; this ensures that changes to the array cannot affect the iteration.
36
36
This is implemented by having the iterator store a reference-counted pointer to the array storage in order to ensure that the storage cannot be freed while the iterator is active.
A nonescapable value is not allowed to escape the local context:
90
+
91
+
- It cannot be assigned to a binding in a larger scope
92
+
- It cannot be returned from the current scope
93
+
90
94
```swift
91
95
// Example: Basic limits on ~Escapable types
92
96
funcf() -> NotEscapable {
@@ -99,9 +103,9 @@ func f() -> NotEscapable {
99
103
```
100
104
101
105
**Note**:
102
-
The section "Returned nonescapable values require lifetime dependency" explains the implications for how you must write initializers.
106
+
The section ["Returned nonescapable values require lifetime dependency"](#Returns) explains the implications for how you must write initializers.
103
107
104
-
Without `~Escapable`, the default for any type is to be escapable. Since `~Escapable` suppresses a capability, you cannot put this in an extension.
108
+
Without `~Escapable`, the default for any type is to be escapable. Since `~Escapable` suppresses a capability, you cannot declare it with an extension.
105
109
106
110
```swift
107
111
// Example: Escapable by default
@@ -159,21 +163,21 @@ func f() {
159
163
}
160
164
```
161
165
162
-
#### Constraints on nonescapable arguments
166
+
#### Constraints on nonescapable parameters
163
167
164
-
A value of nonescapable type received as an argument is subject to the same constraints as any other local variable.
165
-
In particular, a nonescapable `consuming`argument (and all direct copies thereof) must actually be destroyed during the execution of the function.
166
-
This is in contrast to an _escapable_`consuming`argument which can be disposed of by being returned or stored to an instance property or global variable.
168
+
A value of nonescapable type received as an parameter is subject to the same constraints as any other local variable.
169
+
In particular, a nonescapable `consuming`parameter (and all direct copies thereof) must actually be destroyed during the execution of the function.
170
+
This is in contrast to an _escapable_`consuming`parameter which can be disposed of by being returned or stored to an instance property or global variable.
167
171
168
-
#### Values that contain nonescapable values must be nonescapable
172
+
#### Types that contain nonescapable values must be nonescapable
169
173
170
174
Stored struct properties and enum payloads can have nonescapable types if the surrounding type is itself nonescapable.
171
-
(Equivalently, an escapable struct or enum can only contain escapable values.)
175
+
Equivalently, an escapable struct or enum can only contain escapable values.
172
176
Nonescapable values cannot be stored as class properties, since classes are always inherently escaping.
173
177
174
178
```swift
175
179
// Example
176
-
structOuterEscapable {
180
+
structEscapableStruct {
177
181
// 🛑 Escapable struct cannot have nonescapable stored property
As mentioned earlier, a simple return of a nonescapable value is not permitted:
198
202
```swift
@@ -202,7 +206,7 @@ func f() -> NotEscapable { // 🛑 Cannot return a nonescapable type
202
206
}
203
207
```
204
208
205
-
A separate proposal describes “lifetime dependency annotations” that can relax this requirement by tying the lifetime of the returned value to the lifetime of some other object, either an argument to the function or `self`in the case of a method or computed property returning a nonescapable type.
209
+
A separate proposal describes “lifetime dependency annotations” that can relax this requirement by tying the lifetime of the returned value to the lifetime of another binding. The other binding can be a parameter of a function returning a vaule of a nonescapable type, or con be `self`for a method or computed property returning a value of a nonescapable type.
206
210
In particular, struct and enum initializers (which build a new value and return it to the caller) cannot be written without some mechanism similar to that outlined in our companion proposal.
207
211
208
212
#### Globals and static variables cannot be nonescapable
@@ -213,13 +217,13 @@ This implies that they cannot be stored in global or static variables.
Nonescaping closures can capture nonescapable values subject only to the usual exclusivity restrictions.
220
+
Nonescaping closures can capture nonescapable values subject to the usual exclusivity restrictions.
217
221
218
222
Returning a nonescapable value from a closure requires explicit lifetime dependency annotations, as covered in the companion proposal.
219
223
220
224
#### Nonescapable values and concurrency
221
225
222
-
All of the requirements on use of nonescapable values as function arguments and return values also apply to async functions, including those invoked via `async let`.
226
+
All of the requirements on use of nonescapable values as function parameters and return values also apply to async functions, including those invoked via `async let`.
223
227
224
228
The closures used in `Task.init`, `Task.detached`, or `TaskGroup.addTask` are escaping closures and therefore cannot capture nonescapable values.
This can be used in conjunction with other suppressible protocols.
244
-
For example, many general library types will need to be copyable and/or escapable following their contents.
248
+
For example, many general library container types will need to be copyable and/or escapable according to their contents.
245
249
Here's a compact way to declare such a type:
246
250
```swift
247
251
structWrapper<T: ~Copyable &~Escapable> { ... }
@@ -305,9 +309,9 @@ Retrofitting existing generic types so they can support both escapable and nones
305
309
306
310
## Future directions
307
311
308
-
#### `StorageView` type
312
+
#### `Span` type
309
313
310
-
This proposal is being driven in large part by the needs of the `StorageView` type that has been discussed elsewhere.
314
+
This proposal is being driven in large part by the needs of the `Span` type that has been discussed elsewhere.
311
315
Briefly, this type would provide an efficient universal “view” of array-like data stored in contiguous memory.
312
316
Since values of this type do not own any data but only refer to data stored elsewhere, their lifetime must be limited to not exceed that of the owning storage.
313
317
We expect to publish a sample implementation and proposal for that type very soon.
@@ -395,9 +399,9 @@ so it cannot be allowed to contain a nonescapable value.
395
399
396
400
#### Rely on `~Copyable`
397
401
398
-
As part of the `StorageView` design, we considered whether it would suffice to use `~Copyable` instead of introducing a new type concept.
399
-
Andrew Trick's analysis in [Language Support for Bufferview](https://forums.swift.org/t/roadmap-language-support-for-bufferview/66211) concluded that making `StorageView` be non-copyable would not suffice to provide the full semantics we want for that type.
400
-
Further, introducing `StorageView` as `~Copyable` would actually preclude us from later expanding it to be `~Escapable`.
402
+
As part of the `Span` design, we considered whether it would suffice to use `~Copyable` instead of introducing a new type concept.
403
+
Andrew Trick's analysis in [Language Support for Bufferview](https://forums.swift.org/t/roadmap-language-support-for-bufferview/66211) concluded that making `Span` be non-copyable would not suffice to provide the full semantics we want for that type.
404
+
Further, introducing `Span` as `~Copyable` would actually preclude us from later expanding it to be `~Escapable`.
401
405
402
406
The iterator example in the beginning of this document provides another motivation:
403
407
Iterators are routinely copied in order to record a particular point in a collection.
0 commit comments