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/AAAA-stdlib-span-properties.md
+25-62Lines changed: 25 additions & 62 deletions
Original file line number
Diff line number
Diff line change
@@ -76,88 +76,60 @@ In this version, code evolution is not constrained by a closure. Incorrect escap
76
76
77
77
## Detailed Design
78
78
79
-
A computed property getter of an `Escapable` type returning a non-escapable and copyable type (`~Escapable & Copyable`) establishes a borrowing lifetime relationship of the returned value on the callee's binding. As long as the returned value exists (including local copies,) then the callee's binding is being borrowed. In terms of the law of exclusivity, a borrow is a read-only access. Multiple borrows are allowed to overlap, but cannot overlap with any mutation.
79
+
Computed properties returning non-escapable and copyable types (`~Escapable & Copyable`) become possible, requiring no additional annotations. The lifetime of their returned value depends on the type vending them. A `~Escapable & Copyable`value borrows another binding. In terms of the law of exclusivity, a borrow is a read-only access. Multiple borrows are allowed to overlap, but cannot overlap with any mutation.
80
80
81
-
By allowing the language to define lifetime dependencies in this limited way, we can add `Span`-providing properties to standard library types.
81
+
A computed property getter of an `Escapable` type returning a `~Escapable & Copyable` value establishes a borrowing lifetime relationship of the returned value on the callee's binding. As long as the returned value exists (including local copies,) then the callee's binding remains borrowed.
82
+
83
+
A computed property getter of an `~Escapable & Copyable` type returning a `~Escapable & Copyable` value copies the lifetime dependency of the callee. The returned value becomes an additional borrow of the callee's dependency, but is otherwise independent from the callee.
84
+
85
+
A computed property getter of an `~Escapable & ~Copyable` type returning a `~Escapable & Copyable` value establishes a borrowing lifetime relationship of the returned value on the callee's binding. As long as the returned value exists (including local copies,) then the callee's binding remains borrowed.
86
+
87
+
By allowing the language to define lifetime dependencies in these limited ways, we can add `Span`-providing properties to standard library types.
82
88
83
89
#### <aname="extensions"></a>Extensions to Standard Library types
84
90
85
-
The standard library and Foundation will provide `storage` and `bytes`computed properties. These computed properties are the safe and composable replacements for the existing `withUnsafeBufferPointer` and `withUnsafeBytes` closure-taking functions.
91
+
The standard library and Foundation will provide `storage` and computed properties, returning lifetime-dependent `Span` instances. These computed properties are the safe and composable replacements for the existing `withUnsafeBufferPointer` closure-taking functions.
86
92
87
93
```swift
88
94
extensionArray {
89
95
/// Share this `Array`'s elements as a `Span`
90
96
var storage: Span<Element> { get }
91
97
}
92
98
93
-
extensionArraywhereElement:BitwiseCopyable {
94
-
/// Share the bytes of this `Array`'s elements as a `RawSpan`
95
-
var bytes: RawSpan { get }
96
-
}
97
-
98
99
extensionArraySlice {
99
100
/// Share this `Array`'s elements as a `Span`
100
101
var storage: Span<Element> { get }
101
102
}
102
103
103
-
extensionArraySlicewhereElement:BitwiseCopyable {
104
-
/// Share the bytes of this `Array`'s elements as a `RawSpan`
/// Share the underlying bytes of this `Collection`'s elements as a `RawSpan`
159
-
var bytes: RawSpan { get }
160
-
}
161
133
```
162
134
163
135
Conditionally to the acceptance of [`Vector`][SE-0453], we will also add the following:
@@ -167,13 +139,21 @@ extension Vector where Element: ~Copyable {
167
139
/// Share this vector's elements as a `Span`
168
140
var storage: Span<Element> { get }
169
141
}
142
+
```
143
+
144
+
#### Accessing the raw bytes of a `Span`
170
145
171
-
extensionVectorwhereElement:BitwiseCopyable {
172
-
/// Share the underlying bytes of vector's elements as a `RawSpan`
146
+
When a `Span`'s element is `BitwiseCopyable`, we allow viewing the underlying storage as raw bytes with `RawSpan`:
147
+
148
+
```swift
149
+
extensionSpanwhereElement:BitwiseCopyable {
150
+
/// Share the raw bytes of this `Span`'s elements
173
151
var bytes: RawSpan { get }
174
152
}
175
153
```
176
154
155
+
The returned `RawSpan` instance will borrow the same binding as is borrowed by the `Span`.
156
+
177
157
#### Extensions to unsafe buffer types
178
158
179
159
We hope that `Span` and `RawSpan` will become the standard ways to access shared contiguous memory in Swift, but current API provide `UnsafeBufferPointer` and `UnsafeRawBufferPointer` instances to do this. We will provide ways to unsafely obtain `Span` and `RawSpan` instances from them, in order to bridge `UnsafeBufferPointer` to contexts that use `Span`, or `UnsafeRawBufferPointer` to contexts that use `RawSpan`.
All of these unsafe conversions return a value whose lifetime is dependent on the _binding_ of the UnsafeBufferPointer. Note that this does not keep the underlying memory alive, as usual where the `UnsafePointer` family of types is involved. The programmer must ensure that the underlying memory is valid for as long as the `Span` or `RawSpan` are valid.
220
184
221
-
#### Extensions to `Foundation.Data`
185
+
#### Extension to `Foundation.Data`
222
186
223
187
While the `swift-foundation` package and the `Foundation` framework are not governed by the Swift evolution process, `Data` is similar in use to standard library types, and the project acknowledges that it is desirable for it to have similar API when appropriate. Accordingly, we would add the following properties to `Foundation.Data`:
224
188
225
189
```swift
226
190
extensionFoundation.Data {
227
191
// Share this `Data`'s bytes as a `Span`
228
192
var storage: Span<UInt8> { get }
229
-
230
-
// Share this `Data`'s bytes as a `RawSpan`
231
-
var bytes: RawSpan { get }
232
193
}
233
194
```
234
195
@@ -286,12 +247,14 @@ a.append(8)
286
247
During the evolution of Swift, we have learned that closure-based API are difficult to compose, especially with one another. They can also require alterations to support new language features. For example, the generalization of closure-taking API for non-copyable values as well as typed throws is ongoing; adding more closure-taking API may make future feature evolution more labor-intensive. By instead relying on returned values, whether from computed properties or functions, we build for greater composability. Use cases where this approach falls short should be reported as enhancement requests or bugs.
287
248
288
249
#### Giving the properties different names
250
+
289
251
We chose the names `storage` and `bytes` because those reflect _what_ they represent. Another option would be to name the properties after _how_ they represent what they do, which would be `span` and `rawSpan`. It is possible the name `storage` would be deemed to clash too much with existing properties of types that would like to provide views of their internal storage with `Span`-providing properties. For example, the Standard Library's concrete `SIMD`-conforming types have a property `var _storage`. The current proposal means that making this property of `SIMD` types into public API would entail a name change more significant than simply removing its leading underscore.
290
252
291
-
#### Allowing the definition of non-escapable properties of non-escapable types
292
-
The particular case of the lifetime dependence created by a property of a non-escapable type is not as simple as when the parent type is escapable. There are two possible ways to define the lifetime of the new instance: it can either depend on the lifetime of the original instance, or it can acquire the lifetime of the original instance and be otherwise independent. We believe that both these cases can be useful, and therefore defer allowing either until there is a language annotation to differentiate between them.
253
+
#### Disallowing the definition of non-escapable properties of non-escapable types
254
+
255
+
The particular case of the lifetime dependence created by a property of a copyable non-escapable type is not as simple as when the parent type is escapable. There are two possible ways to define the lifetime of the new instance: it can either depend on the lifetime of the original instance, or it can acquire the lifetime of the original instance and be otherwise independent. We believe that both these cases can be useful, but that in the majority of cases the desired behaviour will be to have an independent return value, where the newly returned value borrows the same binding as the callee. Therefore we believe that is reasonable to reserve the unannotated spelling for this more common case.
293
256
294
-
As a consequence of not allowing either of these cases, we cannot define a `bytes` property on a `Span` when its `Element` is `BitwiseCopyable`. This means that we must add the `bytes` properties on each individual type, rather than relying on a conditional property of `Span`.
257
+
The original version of this pitch disallowed this. As a consequence, the `bytes` property had to be added on each individual type, rather than having `bytes` as a conditional property of `Span`.
0 commit comments