Skip to content

Commit 127c206

Browse files
authored
Merge pull request #12 from glessard/non-escapable
Editing suggestions for non-escapable
2 parents 0c6825b + 3656dcc commit 127c206

File tree

1 file changed

+28
-24
lines changed

1 file changed

+28
-24
lines changed

proposals/NNNN-non-escapable.md

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@ This complements the `~Copyable` types added with SE-0390 by introducing another
1616

1717
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.
1818

19-
This feature is a key requirement for the proposed `StorageView` type.
19+
This feature is a key requirement for the proposed `Span` type.
2020

2121
**See Also**
2222

2323
* [SE-0390: Noncopyable structs and enums](https://github.com/apple/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md)
2424
* [Language Support for Bufferview](https://forums.swift.org/t/roadmap-language-support-for-bufferview/66211)
2525
* [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)
2626
* [Ownership Manifesto](https://forums.swift.org/t/manifesto-ownership/5212)
27-
* [Draft StorageView Proposal](https://github.com/apple/swift-evolution/pull/2307)
27+
* [Draft Span Proposal](https://github.com/apple/swift-evolution/pull/2307)
2828
* [Draft Lifetime Dependency Annotations Proposal](https://github.com/apple/swift-evolution/pull/2305)
2929

3030
## Motivation
3131

3232
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.
3434

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.
3636
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.
3737
These safety checks all incur runtime overhead.
3838

@@ -87,6 +87,10 @@ struct NotEscapable: ~Escapable {
8787
```
8888

8989
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+
9094
```swift
9195
// Example: Basic limits on ~Escapable types
9296
func f() -> NotEscapable {
@@ -99,9 +103,9 @@ func f() -> NotEscapable {
99103
```
100104

101105
**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.
103107

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.
105109

106110
```swift
107111
// Example: Escapable by default
@@ -159,21 +163,21 @@ func f() {
159163
}
160164
```
161165

162-
#### Constraints on nonescapable arguments
166+
#### Constraints on nonescapable parameters
163167

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.
167171

168-
#### Values that contain nonescapable values must be nonescapable
172+
#### Types that contain nonescapable values must be nonescapable
169173

170174
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.
172176
Nonescapable values cannot be stored as class properties, since classes are always inherently escaping.
173177

174178
```swift
175179
// Example
176-
struct OuterEscapable {
180+
struct EscapableStruct {
177181
// 🛑 Escapable struct cannot have nonescapable stored property
178182
var nonesc: Nonescapable
179183
}
@@ -183,7 +187,7 @@ enum EscapableEnum {
183187
case nonesc(Nonescapable)
184188
}
185189

186-
struct OuterNonescapable: ~Escapable {
190+
struct NonescapableStruct: ~Escapable {
187191
var nonesc: Nonescapable // OK
188192
}
189193

@@ -192,7 +196,7 @@ enum NonescapableEnum: ~Escapable {
192196
}
193197
```
194198

195-
#### Returned nonescapable values require lifetime dependency
199+
#### <a name="Returns"></a>Returned nonescapable values require lifetime dependency
196200

197201
As mentioned earlier, a simple return of a nonescapable value is not permitted:
198202
```swift
@@ -202,7 +206,7 @@ func f() -> NotEscapable { // 🛑 Cannot return a nonescapable type
202206
}
203207
```
204208

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.
206210
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.
207211

208212
#### Globals and static variables cannot be nonescapable
@@ -213,13 +217,13 @@ This implies that they cannot be stored in global or static variables.
213217
#### Closures and nonescapable values
214218

215219
Escaping closures cannot capture nonescapable values.
216-
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.
217221

218222
Returning a nonescapable value from a closure requires explicit lifetime dependency annotations, as covered in the companion proposal.
219223

220224
#### Nonescapable values and concurrency
221225

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`.
223227

224228
The closures used in `Task.init`, `Task.detached`, or `TaskGroup.addTask` are escaping closures and therefore cannot capture nonescapable values.
225229

@@ -241,7 +245,7 @@ extension Box: Escapable where T: Escapable { }
241245
```
242246

243247
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.
245249
Here's a compact way to declare such a type:
246250
```swift
247251
struct Wrapper<T: ~Copyable & ~Escapable> { ... }
@@ -305,9 +309,9 @@ Retrofitting existing generic types so they can support both escapable and nones
305309

306310
## Future directions
307311

308-
#### `StorageView` type
312+
#### `Span` type
309313

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.
311315
Briefly, this type would provide an efficient universal “view” of array-like data stored in contiguous memory.
312316
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.
313317
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.
395399

396400
#### Rely on `~Copyable`
397401

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`.
401405

402406
The iterator example in the beginning of this document provides another motivation:
403407
Iterators are routinely copied in order to record a particular point in a collection.

0 commit comments

Comments
 (0)