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-lifetime-dependency.md
+27-27
Original file line number
Diff line number
Diff line change
@@ -12,14 +12,16 @@ We would like to propose extensions to Swift's function-declaration syntax that
12
12
These would also be useable with methods that wish to declare a dependency on `self`.
13
13
To reduce the burden of manually adding such annotations, we also propose inferring lifetime dependencies in certain common cases without requiring any additional annotations.
14
14
15
-
This is a key requirement for the `StorageView` type (previously called `BufferView`) being discussed elsewhere, and is closely related to the proposal for `~Escapable` types.
15
+
This is a key requirement for the `Span` type (previously called `BufferView`) being discussed elsewhere, and is closely related to the proposal for `~Escapable` types.
16
16
17
17
**Edited** (Apr 12, 2024): Changed `@dependsOn` to `dependsOn` to match the current implementation.
18
18
19
+
**Edited** (May 2, 2024): Changed `StorageView` and `BufferReference` to `Span` to match the sibling proposal.
20
+
19
21
#### See Also
20
22
21
23
***TODO**: **** Forum thread discussing this proposal
22
-
*[Pitch Thread for StorageView](https://forums.swift.org/t/pitch-safe-access-to-contiguous-storage/69888)
24
+
*[Pitch Thread for Span](https://forums.swift.org/t/pitch-safe-access-to-contiguous-storage/69888)
23
25
*[Forum discussion of BufferView language requirements](https://forums.swift.org/t/roadmap-language-support-for-bufferview)
24
26
*[Proposed Vision document for BufferView language requirements (includes description of ~Escapable)](https://github.com/atrick/swift-evolution/blob/fd63292839808423a5062499f588f557000c5d15/visions/language-support-for-BufferView.md#non-escaping-bufferview)
25
27
@@ -75,12 +77,10 @@ These types are not allowed to escape the local context except in very specific
75
77
A separate proposal explains the general syntax and semantics of `Escapable` and `~Escapable`.
76
78
77
79
By themselves, nonescapable types have severe constraints on usage.
78
-
For example, consider a hypothetical `BufferReference` type that is similar to the standard library `UnsafeBufferPointer` or the `StorageView` type that is being proposed for inclusion in the standard library.
79
-
It simply holds a pointer and size and can be used to access data stored in a contiguous block of memory.
80
-
(We are not proposing this type; it is shown here merely for illustrative purposes.)
80
+
For example, consider a hypothetical `Span` type that is similar type that is being proposed for inclusion in the standard library. It simply holds a pointer and size and can be used to access data stored in a contiguous block of memory. (We are not proposing this type; it is shown here merely for illustrative purposes.)
81
81
82
82
```swift
83
-
structBufferReference<T>: ~Escapable {
83
+
structSpan<T>: ~Escapable {
84
84
privatevar base: UnsafePointer<T>
85
85
privatevar count: Int
86
86
}
@@ -94,35 +94,35 @@ In the most common cases, these constraints can be inferred automatically.
94
94
95
95
To make the semantics clearer, we’ll begin by describing how one can explicitly specify a lifetime constraint in cases where the default inference rules do not apply.
96
96
97
-
Let’s consider adding support for our hypothetical `BufferReference` type to `Array`.
98
-
Our proposal would allow you to declare an `array.bufferReference()` method as follows:
97
+
Let’s consider adding support for our hypothetical `Span` type to `Array`.
98
+
Our proposal would allow you to declare an `array.span()` method as follows:
The annotation `dependsOn(self)` here indicates that the returned value must not outlive the array that produced it.
109
109
Conceptually, it is a continuation of the function's borrowing access:
110
-
the array is being borrowed by the function while the function executes and then continues to be borrowed by the `BufferReference` for as long as the return value exists.
110
+
the array is being borrowed by the function while the function executes and then continues to be borrowed by the `Span` for as long as the return value exists.
111
111
Specifically, the `dependsOn(self)` annotation in this example informs the compiler that:
112
112
113
-
* The array must not be destroyed until after the `BufferReference<Element>` is destroyed.
113
+
* The array must not be destroyed until after the `Span<Element>` is destroyed.
114
114
This ensures that use-after-free cannot occur.
115
-
* The array must not be mutated while the `BufferReference<Element>` value exists.
115
+
* The array must not be mutated while the `Span<Element>` value exists.
116
116
This follows the usual Swift exclusivity rules for a borrowing access.
117
117
118
118
#### Scoped Lifetime Dependency
119
119
120
-
Let’s consider another hypothetical type: a `MutatingBufferReference<T>` type that could provide indirect mutating access to a block of memory.
120
+
Let’s consider another hypothetical type: a `MutatingSpan<T>` type that could provide indirect mutating access to a block of memory.
@@ -131,21 +131,21 @@ The `dependsOn(to)` annotation indicates that the returned value depends on the
131
131
Because `count` is not mentioned in the lifetime dependency, that argument does not participate.
132
132
Similar to the previous example:
133
133
134
-
* The array will not be destroyed until after the `MutatingBufferReference<Element>` is destroyed.
134
+
* The array will not be destroyed until after the `MutatingSpan<Element>` is destroyed.
135
135
* No other read or write access to the array will be allowed for as long as the returned value exists.
136
136
137
137
In both this and the previous case, the lifetime of the return value is "scoped" to the lifetime of the original value.
138
138
Because lifetime dependencies can only be attached to nonescapable values, types that contain pointers will generally need to be nonescapable in order to provide safe semantics.
139
-
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as an Array or similar container) is providing a nonescapable value (such as the `BufferReference` or `MutatingBufferReference` in these examples).
139
+
As a result, **scoped lifetime dependencies** are the only possibility whenever an `Escapable` value (such as an Array or similar container) is providing a nonescapable value (such as the `Span` or `MutatingSpan` in these examples).
140
140
141
141
#### Copied Lifetime Dependency
142
142
143
143
The case where a nonescapable value is used to produce another nonescapable value is somewhat different.
144
-
Here's a typical example that constructs a new `BufferReference` from an existing one:
144
+
Here's a typical example that constructs a new `Span` from an existing one:
@@ -155,12 +155,12 @@ Recall that nonescapable values such as these represent values that are already
155
155
156
156
For a `consuming` method, the return value cannot have a scoped lifetime dependency on the original value, since the original value no longer exists when the method returns.
157
157
Instead, the return value must "copy" the lifetime dependency from the original:
158
-
If the original `BufferReference` was borrowing some array, the new `BufferReference` will continue to borrow the same array.
158
+
If the original `Span` was borrowing some array, the new `Span` will continue to borrow the same array.
159
159
160
160
This supports coding patterns such as this:
161
161
```swift
162
162
let a: Array<Int>
163
-
let ref1 = a.bufferReference() // ref1 cannot outlive a
163
+
let ref1 = a.span() // ref1 cannot outlive a
164
164
let ref2 = ref1.drop(4) // ref2 also cannot outlive a
165
165
```
166
166
@@ -413,21 +413,21 @@ We propose above putting the annotation on the return value, which we believe ma
413
413
It would also be possible to put an annotation on the parameters instead:
An earlier version of this proposal advocated using the existing `borrow`/`mutate`/`consume`/`copy` keywords to specify a particular lifetime dependency semantic:
This was changed after we realized that there was in practice almost always a single viable semantic for any given situation, so the additional refinement seemed unnecessary.
433
433
@@ -483,7 +483,7 @@ We expect to address this in the near future in a separate proposal.
483
483
It should be possible to return containers with collections of lifetime-constrained elements.
484
484
For example, a container may want to return a partition of its contents:
0 commit comments