# SE-0447: Span: Safe Access to Contiguous Storage

**URL:** <https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676>\
**Category:** Proposal Reviews\
**Created:** [September 18, 2024, 4:40am UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676 "2024-09-18T04:40:29Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [September 23, 2024, 8:34pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/22 "2024-09-23T20:34:08Z")

</div>

Of course, `Span` on its own doesn't really attempt to convey this non-owning-ness either.

---

<div class="post-metadata">

**Author:** ![Alejandro](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alejandro/32/46197_2.png) [@Alejandro](https://forums.swift.org/u/Alejandro)\
**Post date:** [September 23, 2024, 8:52pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/23 "2024-09-23T20:52:56Z")

</div>

No, but like @glessard mentioned earlier there are other languages using this name for the same construct at least in C++ and C# (Rust names this slice, but it has a special syntax in source).

---

<div class="post-metadata">

**Author:** ![David\_Smith](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_smith/32/37508_2.png) [@David\_Smith](https://forums.swift.org/u/David_Smith)\
**Post date:** [September 23, 2024, 9:03pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/24 "2024-09-23T21:03:16Z")

</div>

Yeah, this is what I was getting at with "under this ontology". If we understand this to be a _kind of buffer_ then the extra words describe _what kind_. If we understand it as its own standalone thing, then the separate word for that thing can have this meaning.

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [September 23, 2024, 9:45pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/25 "2024-09-23T21:45:13Z")

</div>

I think this API will be useful. I think we should look at deprecating some of the buffer pointer API on other types that, in a safe world, would use spans instead. If somebody _really_ needs a buffer pointer, they can get it from the span.

I am a bit bothered by `RawSpan` as a different type. I understand that it mirrors our pointer types, but it does add complexity to the API surface. As a strawman… `Span<Never>`? It's sort of saying "this is a `Span`, and you can never access its elements [because it doesn't have any because it's untyped]"? (I'm not _actually_ advocating for `Span<Never>` here. Weird. Just trying to think about how we could avoid a separate `RawSpan` type.)

---

<div class="post-metadata">

**Author:** ![glessard](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glessard/32/409_2.png) [@glessard](https://forums.swift.org/u/glessard)\
**Post date:** [September 23, 2024, 9:54pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/26 "2024-09-23T21:54:08Z")

</div>

Something to consider is that this is the first of a family of types. We need to add a mutable variant (for delegating mutations), and an output-only variant (for delegating initialization safely), at least. The names for these could be `MutableSpan` and `OutputSpan`. `Span` definitely has the merit of being short and nearly particle-like.

---

<div class="post-metadata">

**Author:** ![j-f1](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/j-f1/32/12287_2.png) [@j-f1](https://forums.swift.org/u/j-f1)\
**Post date:** [September 23, 2024, 10:00pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/27 "2024-09-23T22:00:39Z")

</div>

> [@grynspan](#):
>
> As a strawman… `Span<Never>`? It's sort of saying "this is a `Span`, and you can never access its elements [because it doesn't have any because it's untyped]"? (I'm not _actually_ advocating for `Span<Never>` here. Weird. Just trying to think about how we could avoid a separate `RawSpan` type.)

I actually like the idea of `Span<Never>` — it would handily make all of the typed APIs unavailable, and you could put the untyped APIs directly onto the typed type so there’s no need to upcast.

---

<div class="post-metadata">

**Author:** ![glessard](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glessard/32/409_2.png) [@glessard](https://forums.swift.org/u/glessard)\
**Post date:** [September 23, 2024, 10:08pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/28 "2024-09-23T22:08:14Z")

</div>

We had initially considered putting the `unsafeLoad(as:)` and related API on `Span<UInt8>`, but that does two things that don't sit well: it hides useful API in an unusual place (in extensions specific to an element type), and raises the question of what's special about `UInt8`? `RawSpan` has an advantage of not relying on generic specialization for good performance.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [September 23, 2024, 10:08pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/29 "2024-09-23T22:08:36Z")

</div>

You could certainly add special operations to `Span<Never>`, but you'd also need to remove / specialize all of the normal operations that are specified to work with values of the element type. The operation sets are basically totally independent.

---

<div class="post-metadata">

**Author:** ![ellie20](https://avatars.discourse-cdn.com/v4/letter/e/6f9a4e/32.png) [@ellie20](https://forums.swift.org/u/ellie20)\
**Post date:** [September 23, 2024, 10:30pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/30 "2024-09-23T22:30:13Z")

</div>

I think an interesting direction would be to create safe pointer types with names directly corresponding to the unsafe ones. Not only `BufferPointer` and `RawBufferPointer`, but also `Pointer`, `MutablePointer`, etc.

It could be helpful to give the safe and unsafe pointer types the same APIs to facilitate switching between the two, like how `CheckedContinuation` and `UnsafeContinuation` have the same APIs. A safe `Pointer` type could have a `pointee` property consistent with the `UnsafePointer` type, instead of the property being named something different like `referent`.

I wonder to what extent the association of "pointer" with unsafety is inherent and to what extent it is changeable. It could be that C has irreversibly associated "pointer" with unsafety, but maybe Swift can overcome the association. In Rust, "reference" refers to safe pointers. In C++, "reference" refers to unsafe pointers that are automatically dereferenced, and "pointer" refers to both unsafe pointers and safe(-ish) smart pointers like `std::unique_ptr`. In Java, object references are referred to as both "pointers" (in `NullPointerException`) and "references" (in `WeakReference`). In Cyclone, "pointer" refers to both safe and unsafe pointers.

---

<div class="post-metadata">

**Author:** ![lorentey](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lorentey/32/1299_2.png) [@lorentey](https://forums.swift.org/u/lorentey)\
**Post date:** [September 24, 2024, 12:17am UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/31 "2024-09-24T00:17:14Z")

</div>

I strongly oppose naming this core type something clumsy like `BufferPointer`. _Please_ let's not do that. Spans aren't "buffers"; they also aren't pointers to buffers.

`Span` is an extremely strong name; it has a punch that befits the importance of this abstraction. It also happens to be in preexisting use in the same context.

Names this good are rare; when we find one, we need to recognize it as such as and celebrate our good luck.

---

<div class="post-metadata">

**Author:** ![lorentey](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lorentey/32/1299_2.png) [@lorentey](https://forums.swift.org/u/lorentey)\
**Post date:** [September 24, 2024, 12:47am UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/32 "2024-09-24T00:47:17Z")

</div>

> ```swift
> extension Span where Element: ~Copyable {
> public subscript(_ position: Int) -> Element { _read }
> }
> 
> ```
> 
> Note that we use a `_read` accessor for the subscript, a requirement in order to `yield` a borrowed non-copyable `Element` (see ["Coroutines"](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0447-span-access-shared-contiguous-storage.md#Coroutines).) This will be updated to a final syntax at a later time, understanding that we intend the replacement to be source-compatible.

This is not exactly correct. We now know that `_read` accessor coroutines will not suffice for element access -- the final form of `Span`'s subscripts will need to use very different semantics than what is being promised here.

The elements of a span are guaranteed to exist as long as the span does. We'll need the subscript accessors to fully embrace this fact: the borrows of the elements that we produce through subscript access need to have precisely the same lifetime dependencies as the span itself.

(Read accessors are allowed to materialize their result on demand; so the borrows we get from them are necessarily tied to the specific access to the span itself. This is far too complicated and it results in unusably narrow lifetime dependencies. To be able to build useful abstractions around spans (and borrowing access in general), we need to model direct accesses as direct accesses.)

We've been assuming that a coroutine-based (or `unsafeAddress`-based) `Span` subscript will be source-compatible with the eventual borrowing accessor construct (which does not exist yet). However, this is just an assumption; it should be called out in the proposal, and it deserves critical review.

---

<div class="post-metadata">

**Author:** ![lorentey](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lorentey/32/1299_2.png) [@lorentey](https://forums.swift.org/u/lorentey)\
**Post date:** [September 24, 2024, 1:58am UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/33 "2024-09-24T01:58:52Z")

</div>

API nitpicks:

### Index validation members

```swift
extension Span where Element: ~Copyable {
  public func boundsContain(_ index: Int) -> Bool
  public func boundsContain(_ indices: Range<Int>) -> Bool
  public func boundsContain(_ indices: ClosedRange<Int>) -> Bool
}

```

As the proposal admits, these are not good names. We should not add badly named interfaces to the Swift Standard Library.

I suggest we should remove these members from the `Span` types. Alternatively, I suggest giving them the following names:

```swift
extension Span where Element: ~Copyable {
  public func isValidIndex(_ index: Int) -> Bool
  public func isValidSubrange(_ subrange: Range<Int>) -> Bool
  public func isValidSubrange(_ subrange: ClosedRange<Int>) -> Bool
}

extension RawSpan {
  public func isValidByteOffset(_ offset: Int) -> Bool
  public func isValidByteOffsetRange(_ subrange: Range<Int>) -> Bool
  public func isValidByteOffsetRange(_ subrange: ClosedRange<Int>) -> Bool
}

```

The `ClosedRange` overloads are rubbing me the wrong way -- why do we need those? Should we also have a generic `isValidSubrange` that takes any `RangeExpression`? I think I'd be happier if we didn't have any of these.

**Update:** I've now remembered that [I already suggested these](https://forums.swift.org/t/pitch-2-safe-access-to-contiguous-storage/72745/17) in public, way back in June. This makes me a bit confused.

If we can only find "not ideal" names for these predicates, then I don't see why we would want to propose them as public API. After all, no preexisting standard container comes with such operations. The proposal does not justify why they'd need to be unique to `Span`, but neither does it mention the obvious alternative: that we'd need to add similar predicates to the `UnsafeBufferPointer` types, too.

I therefore suggest that these operations be removed, deferring them to a potential future proposal that properly introduces them in the general stdlib, rather than isolating their discussion to a single type. Clearly, we are not ready to do that in this proposal.

(Any adopters of `Span` types will be able to validate indices and offsets the obvious way -- by manually checking that they're within `0 ..< count`. This is similar to how we are currently forced to implement index validation in code that deals with `UnsafeBufferPointer`.) **(End of update.)**

### Structural containment checks

I second the idea of removing `isWithin(_:)`, subsuming it into `indicesWithin(_:)`.

However, I think the proposed behavior of the `indicesWithin(_:)` method is quite inconsistent with preexisting API design practice for container types. It is proposed to be a method on a container type that returns the container's index type, but the indices returned belong to some other container, not `self`. This is highly irregular. I believe it to be without precedent in/near the Standard Library, and I do not think we'd want to establish it as a viable pattern.

I suggest to turn the `indicesWithin` method inside out (swapping its `self` with its argument), and rename it to `subrange(of:)`:

```swift
extension Span where Element: ~Copyable {
  /// Returns the index range where the memory of `span` is located within
  /// `self`, or `nil` if `span` is not a subspan of `self`.
  ///
  /// - Parameters:
  /// - span: a potential subspan of `self`
  /// - Returns: A range of indices within `self` corresponding to `span`, or `nil` if there aren't any.
  /// - Complexity: O(1)
  public func subrange(of span: borrowing Self) -> Range<Int>?
}

```

`indices(of:)` would also be a viable alternative spelling for this.

This suggests `byteOffsets(of:)` to be the name of the analogue method on `RawSpan`:

```swift
extension RawSpan {
  public func byteOffsets(of span: borrowing Self) -> Range<Int>?
}

```

### On `indices`

> [@simonomi](#):
>
> I see that in the implementation, `_indices` is underscored, but in my opinion it should be publicly visible, even if `Span` doesn't conform to `Collection`. (A hypothetical non-escapable non-copyable collection protocol would still have that requirement, right?)

I would not automatically expect a hypothetical future container protocol that supports noncopyable conforming types (and elements) to come with an `indices` property.

FWIW, the [very early draft](https://github.com/apple/swift-collections/blob/future/Sources/Future/Containers/Container.swift) we have for such a protocol does not come with one.

Part of the problem is that there is a fundamental need to avoid clashing with the `indices` property in `Collection`. Some types will want to conform to both protocols, so the noncopyable-flavored protocol can only come with `indices` if it can be made fully compatible with `Collection`'s requirements. Unfortunately, the new protocol's `indices` type would need to be nonescapable, which makes this unlikely to work: it seems [highly unlikely](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0427-noncopyable-generics.md#associated-types-without-defaulting-behavior) that `Collection` will ever be generalized to support nonescapable `Indices` associated types.

(The default value of this new, noncopyable-flavored `Indices` associated type would need to be a type that holds a borrow of the original generic noncopyable container. Borrows are inherently nonescapable, and so a type that contains a borrow would itself need to be nonescapable. Note that we cannot express stored borrows in today's Swift, not even with experimental feature flags.)

Therefore, while it is not entirely impossible that a new container protocol would provide something equivalent to `indices`, but (1) it would probably need to come with a different name, and (2) it would also require language constructs that do not exist yet.

I think this makes it a bad idea to ship `Span` with an `indices` property today. Its implementation would be effectively `0 ..< self.count`; we do not urgently _need_ a named property to avoid typing that. Once the dust has settled a bit on the new container protocols, then we may revisit this issue. (For example, if the container protocols end up not having anything like an `indices` view, then that makes `Span` free to add one.)

### The lack of a practical use case

I am of course fully on board with adding the `Span`/`RawSpan` types to the Standard Library. But I question the wisdom of proposing them _now_: without initializers, and without any other way to produce actual span instances, the proposed span types aren't going to be actually usable for anything in practice.

Therefore, I think it would be pointless to actually add `Span` and `RawSpan` to the Standard Library in their proposed partial form. This proposal is incomplete and useless without crucial followup work that (1) properly defines/explains lifetime dependencies and (2) that introduces the missing span initializers. SE-0447 should not ship in a Swift release without that followup work.

At the moment, this proposal is a didactic crutch at best. It is going to allow the lifetimes proposal to tie its concepts to concrete motivating code examples that will be far more useful than the usual half-baked foo/bar illustrations. Those examples will breath life into `Span`, giving it its true purpose. (At worst, it encourages us to make premature, but binding API decisions without fully understanding the ultimate role (and unique constraints of) this type. It does not help that the proposal (for whatever reason) appears to intentionally propose suboptimal names for much of what little API it does define. 🤨)

The proposal suggests that it would be possible to implement `withSpan`/`withBytes` methods without the need to reason about lifetime dependencies. I don't think that is true -- in fact, I believe that such higher order functions establish far more complicated lifetime dependencies than a function that directly returns a `Span`. We currently lack the means to reason about these dependencies; and I don't believe it would be okay to introduce API that Swift developers cannot properly understand. (This issue also applies to the subscripts that are in the normative part of this proposal, as well as the `UnsafePointer.pointee` and the `UnsafeBufferPointer.subscript` generalizations we shipped in SE-0437. All of these have deep semantic problems, especially with noncopyable pointees/elements.)

---

<div class="post-metadata">

**Author:** ![rvsrvs](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rvsrvs/32/5270_2.png) [@rvsrvs](https://forums.swift.org/u/rvsrvs)\
**Post date:** [September 24, 2024, 1:17pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/34 "2024-09-24T13:17:04Z")

</div>

I'm trying to get caught up on how Span will work and am confused about the provided toolchain.

Given that all initializers for Span are dependent on lifetime annotations which being proposed separately, are there flags in the toolchain I can turn on which would allow me to actually create and use Span in code? Or should be only be reviewing API here? I'd much prefer the former as I have specific use cases in mind I'd like to try out.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [September 24, 2024, 1:19pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/35 "2024-09-24T13:19:29Z")

</div>

The provided toolchains should have the `withSpan` API on `Array`. As noted at top-of-thread, the `withSpan` API is not actually being proposed, but is provided as a way to create a `Span` and play around with it.

---

<div class="post-metadata">

**Author:** ![rvsrvs](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rvsrvs/32/5270_2.png) [@rvsrvs](https://forums.swift.org/u/rvsrvs)\
**Post date:** [September 24, 2024, 1:22pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/37 "2024-09-24T13:22:29Z")

</div>

Ah, I had misunderstood. I will defer a review. The use cases I have in mind need lifetime annotations. Thanks @Jumhyn !

---

<div class="post-metadata">

**Author:** ![orobio](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/orobio/32/5512_2.png) [@orobio](https://forums.swift.org/u/orobio)\
**Post date:** [September 26, 2024, 11:52am UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/38 "2024-09-26T11:52:15Z")

</div>

> [@glessard](#):
>
> The word "unchecked" is all over the standard library, though often in underscored position. It does have at least one public use in `Range.init(uncheckedBounds:)`.

For public use, it doesn’t seem to be very common then.

There also is `@unchecked Sendable`, but in that case ‘unsafe’ was deliberately not used, because `@unsafe Sendable` could give the impression that it would be unsafe to send. The unchecked subscript API is definitely unsafe to use, so that is a different situation.

I can imagine it could be good to be more specific about the type of unsafety, but I agree with @tbkka that it can be convenient to be able to grep for ‘unsafe’. Additionally, it is a clear trigger for users and code reviewers. Ideally, Swift would have the concept of an unsafe function, like Rust, and force visibility in that way; then the argument label becomes less important.

---

<div class="post-metadata">

**Author:** ![glessard](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glessard/32/409_2.png) [@glessard](https://forums.swift.org/u/glessard)\
**Post date:** [September 26, 2024, 8:32pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/39 "2024-09-26T20:32:44Z")

</div>

> [@orobio](#):
>
> There also is `@unchecked Sendable`, but in that case ‘unsafe’ was deliberately not used, because `@unsafe Sendable` could give the impression that it would be unsafe to send. The unchecked subscript API is definitely unsafe to use, so that is a different situation.

I feel they're similar usages: the safety of an `@unchecked Sendable` conformance relies on a promise that necessary invariants aren't violated; it _could_ involve undefined behaviour if the isolation isn't done correctly. The `unchecked:` subscript relies on a promise that you know the offset you're passing is in bounds; if it is, then it's perfectly safe; otherwise an out-of-bounds access could involve undefined behaviour.

Note that the `unchecked:` subscripts will have an `@unsafe` annotation, as per the "WarnUnsafe" experimental feature.

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [September 26, 2024, 8:51pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/40 "2024-09-26T20:51:12Z")

</div>

> [@glessard](#):
>
> Note that the `unchecked:` subscripts will have an `@unsafe` annotation, as per the "WarnUnsafe" experimental feature.

This feature has not yet been discussed or pitched ;)

---

<div class="post-metadata">

**Author:** ![glessard](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/glessard/32/409_2.png) [@glessard](https://forums.swift.org/u/glessard)\
**Post date:** [September 26, 2024, 8:52pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/41 "2024-09-26T20:52:07Z")

</div>

Indeed not yet.

---

<div class="post-metadata">

**Author:** ![orobio](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/orobio/32/5512_2.png) [@orobio](https://forums.swift.org/u/orobio)\
**Post date:** [September 26, 2024, 8:52pm UTC](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676/42 "2024-09-26T20:52:39Z")

</div>

They are very similar, but the subtle difference is that in one case it’s the author of the API that makes the promise, and in the other case it’s the user of the API.

> [@glessard](#):
>
> Note that the `unchecked:` subscripts will have an `@unsafe` annotation, as per the "WarnUnsafe" experimental feature.

I hadn’t heard of this, but it sounds promising!

[Previous page](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676.md?page=1)

[Next page](https://forums.swift.org/t/se-0447-span-safe-access-to-contiguous-storage/74676.md?page=3)
