Skip to content

Commit 49668a2

Browse files
committed
move bytes to be a conditional property of Span
1 parent 31f8031 commit 49668a2

File tree

1 file changed

+25
-62
lines changed

1 file changed

+25
-62
lines changed

proposals/AAAA-stdlib-span-properties.md

Lines changed: 25 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -76,88 +76,60 @@ In this version, code evolution is not constrained by a closure. Incorrect escap
7676

7777
## Detailed Design
7878

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

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

8389
#### <a name="extensions"></a>Extensions to Standard Library types
8490

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

8793
```swift
8894
extension Array {
8995
/// Share this `Array`'s elements as a `Span`
9096
var storage: Span<Element> { get }
9197
}
9298

93-
extension Array where Element: BitwiseCopyable {
94-
/// Share the bytes of this `Array`'s elements as a `RawSpan`
95-
var bytes: RawSpan { get }
96-
}
97-
9899
extension ArraySlice {
99100
/// Share this `Array`'s elements as a `Span`
100101
var storage: Span<Element> { get }
101102
}
102103

103-
extension ArraySlice where Element: BitwiseCopyable {
104-
/// Share the bytes of this `Array`'s elements as a `RawSpan`
105-
var bytes: RawSpan { get }
106-
}
107-
108104
extension ContiguousArray {
109105
/// Share this `Array`'s elements as a `Span`
110106
var storage: Span<Element> { get }
111107
}
112108

113-
extension ContiguousArray where Element: BitwiseCopyable {
114-
/// Share the bytes of this `Array`'s elements as a `RawSpan`
115-
var bytes: RawSpan { get }
116-
}
117-
118109
extension String.UTF8View {
119110
/// Share this `UTF8View`'s code units as a `Span`
120111
var storage: Span<Unicode.UTF8.CodeUnit> { get }
121-
122-
/// Share this `UTF8View`'s code units as a `RawSpan`
123-
var bytes: RawSpan { get }
124112
}
125113

126114
extension Substring.UTF8View {
127115
/// Share this `UTF8View`'s code units as a `Span`
128116
var storage: Span<Unicode.UTF8.CodeUnit> { get }
129-
130-
/// Share this `UTF8View`'s code units as a `RawSpan`
131-
var bytes: RawSpan { get }
132117
}
133118

134119
extension CollectionOfOne {
135120
/// Share this `Collection`'s element as a `Span`
136121
var storage: Span<Element> { get }
137122
}
138123

139-
extension CollectionOfOne where Element: BitwiseCopyable {
140-
/// Share the bytes of this `Collection`'s element as a `RawSpan`
141-
var bytes: RawSpan { get }
142-
}
143-
144124
extension SIMD where Scalar: BitwiseCopyable {
145125
/// Share this vector's elements as a `Span`
146126
var storage: Span<Scalar> { get }
147-
148-
/// Share this vector's underlying bytes as a `RawSpan`
149-
var bytes: RawSpan { get }
150127
}
151128

152129
extension KeyValuePairs {
153130
/// Share this `Collection`'s elements as a `Span`
154131
var storage: Span<(Key, Value)> { get }
155132
}
156-
157-
extension KeyValuePairs where Element: BitwiseCopyable {
158-
/// Share the underlying bytes of this `Collection`'s elements as a `RawSpan`
159-
var bytes: RawSpan { get }
160-
}
161133
```
162134

163135
Conditionally to the acceptance of [`Vector`][SE-0453], we will also add the following:
@@ -167,13 +139,21 @@ extension Vector where Element: ~Copyable {
167139
/// Share this vector's elements as a `Span`
168140
var storage: Span<Element> { get }
169141
}
142+
```
143+
144+
#### Accessing the raw bytes of a `Span`
170145

171-
extension Vector where Element: 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+
extension Span where Element: BitwiseCopyable {
150+
/// Share the raw bytes of this `Span`'s elements
173151
var bytes: RawSpan { get }
174152
}
175153
```
176154

155+
The returned `RawSpan` instance will borrow the same binding as is borrowed by the `Span`.
156+
177157
#### Extensions to unsafe buffer types
178158

179159
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`.
@@ -189,46 +169,27 @@ extension UnsafeMutableBufferPointer {
189169
var storage: Span<Element> { get }
190170
}
191171

192-
extension UnsafeBufferPointer where Element: BitwiseCopyable {
193-
/// Unsafely view this buffer as a `RawSpan`
194-
var bytes: RawSpan { get }
195-
}
196-
197-
extension UnsafeMutableBufferPointer where Element: BitwiseCopyable {
198-
/// Unsafely view this buffer as a `RawSpan`
199-
var bytes: RawSpan { get }
200-
}
201-
202172
extension UnsafeRawBufferPointer {
203-
/// Unsafely view this buffer as a `Span`
204-
var storage: Span<Element> { get }
205-
206173
/// Unsafely view this raw buffer as a `RawSpan`
207174
var bytes: RawSpan { get }
208175
}
209176

210177
extension UnsafeMutableRawBufferPointer {
211-
/// Unsafely view this buffer as a `Span`
212-
var storage: Span<Element> { get }
213-
214178
/// Unsafely view this raw buffer as a `RawSpan`
215179
var bytes: RawSpan { get }
216180
}
217181
```
218182

219183
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.
220184

221-
#### Extensions to `Foundation.Data`
185+
#### Extension to `Foundation.Data`
222186

223187
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`:
224188

225189
```swift
226190
extension Foundation.Data {
227191
// Share this `Data`'s bytes as a `Span`
228192
var storage: Span<UInt8> { get }
229-
230-
// Share this `Data`'s bytes as a `RawSpan`
231-
var bytes: RawSpan { get }
232193
}
233194
```
234195

@@ -286,12 +247,14 @@ a.append(8)
286247
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.
287248

288249
#### Giving the properties different names
250+
289251
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.
290252

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

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

296259
## <a name="directions"></a>Future directions
297260

0 commit comments

Comments
 (0)