# \[Pitch\] Generalize ContiguousBytes to support Span et al

**URL:** <https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082>\
**Category:** Foundation\
**Created:** [November 7, 2025, 8:18pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082 "2025-11-07T20:18:02Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [November 7, 2025, 8:18pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/1 "2025-11-07T20:18:02Z")

</div>

Hi all,

The `ContiguousBytes` protocol is there to describe types that can vend storage into their underlying bytes, such as unsafe buffer pointers, arrays, and `Data`. However, the current design of `ContiguousBytes` does not work with the `Span` family of types, because it assumes that the `Self` type is both `Copyable` and `Escapable`. This proposal generalizes `ContiguousBytes` to support non-copyable and non-escapable types, makes `InlineArray` and the various `Span` types conform to it, and provides a safe counterpart to the `withUnsafeBytes` requirement of `ContiguousBytes`.

I propose updating `ContiguousBytes` to support `Span` et al by changing its definition to this:

```swift
public protocol ContiguousBytes: ~Escapable, ~Copyable {
    /// Calls the given closure with the contents of underlying storage.
    ///
    /// - note: Calling `withUnsafeBytes` multiple times does not guarantee that
    /// the same buffer pointer will be passed in every time.
    /// - warning: The buffer argument to the body should not be stored or used
    /// outside of the lifetime of the call to the closure.
    func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R

    /// Calls the given closure with the contents of underlying storage.
    ///
    /// - note: Calling `withBytes` multiple times does not guarantee that
    /// the same span will be passed in every time.
    func withBytes<R, E>(_ body: (RawSpan) throws(E) -> R) throws(E) -> R
}

```

... and then making the `Span`, `MutableSpan`, `RawSpan`, `MutableRawSpan`, `UTF8Span`, and `InlineArray` types conform to it.

Full proposal is [here](https://github.com/DougGregor/swift-foundation/blob/contiguousbytes-span-proposal/Proposals/nnnn-ContiguousBytes-Span.md). Implementation is [here](https://github.com/swiftlang/swift-foundation/pull/1565).

Thoughts?

Doug

---

<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:** [November 7, 2025, 8:26pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/2 "2025-11-07T20:26:58Z")

</div>

Seems straightforwardly good. It occurs to me that we should probably figure out some sort of overarching strategy for this and `withContiguousStorageIfAvailable` in terms of which one is “preferred” (i.e. checked-for first) in situations where we’re dynamically discovering which fast paths are available.

---

<div class="post-metadata">

**Author:** ![jmschonfeld](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jmschonfeld/32/20922_2.png) [@jmschonfeld](https://forums.swift.org/u/jmschonfeld)\
**Post date:** [November 7, 2025, 8:51pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/3 "2025-11-07T20:51:48Z")

</div>

Thanks for thinking through this! Overall, this looks like a good direction to me in order to make the existing `ContiguousBytes` protocol better in a world where we’re moving towards span types. I think that there’s still discussion to be had that the span proposals alluded to around what _new_ APIs should be using to accept bytes as input (since `ContiguousBytes` has its issues as well and we may want to move to a world where APIs just use `RawSpan` directly / there is some automatic conversion to `RawSpan`). That being said, I don’t think that precludes us from improving `ContiguousBytes` via your proposal here to help in cases where `ContiguousBytes` is already used today. Overall just a few general questions:

## Availability

Will these new declarations (either the requirement or the default implementation come with availability)? I assume the default implementation we can define as `@_alwaysEmitIntoClient` and therefore wouldn’t come with availability, but what about the protocol requirement - because the default implementation is always available will that not have availability either, or are there availability constraints on Darwin platforms to keep in mind for adoption here?

## `withUnsafeBytes` Typed Throws Adoption

Your implementation PR also updates the `ContiguousBytes.withUnsafeBytes` requirement to adopt typed throws, but I don’t think I see that mentioned in the proposal. Just to clarify, is that also a proposed change here, and are there any source or ABI compatibility impacts when doing so that we should be aware of?

## `OutputSpan`

Should we also be adding a conformance to `Output(Raw)Span`? It’s simple enough to take an output span and call `.span` to get a `Span` which would conform, but the same argument can be said for types like `InlineArray` and `UTF8Span` which are gaining a conformance here, so would it be consistent to include `OutputSpan`?

---

<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:** [November 7, 2025, 8:52pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/4 "2025-11-07T20:52:06Z")

</div>

This is great!

I have a minor nit with the generic signature for `withBytes()` especially if it is to be codified in ABI: we should make sure that the order of the parameters in the angle brackets is the same as the order in the declaration. This has prevented us from updating the syntax of some stdlib functions to use anonymous generic types (`some Protocol`) in the past. I have no idea what syntax updates could occur here, but let’s not let this mistake occur again!

---

<div class="post-metadata">

**Author:** ![fclout](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/fclout/32/36155_2.png) [@fclout](https://forums.swift.org/u/fclout)\
**Post date:** [November 7, 2025, 8:56pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/5 "2025-11-07T20:56:18Z")

</div>

I imagine we have `withBytes` instead of a borrowing `bytes` property because we can’t have these yet in protocols?

---

<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:** [November 7, 2025, 9:06pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/6 "2025-11-07T21:06:16Z")

</div>

There’s that, but also because a correct default implementation can’t be written.

---

<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:** [November 8, 2025, 12:23am UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/7 "2025-11-08T00:23:01Z")

</div>

I believe we should actually take this opportunity to move the protocol to the standard library. It is fundamentally valuable to be able to tell in advance if a particular sequence (or other value) has contiguous storage, which enables various fast paths. Having the protocol up in Foundation forces a dependency on a rather large library.

---

<div class="post-metadata">

**Author:** ![benrimmington](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/benrimmington/32/695_2.png) [@benrimmington](https://forums.swift.org/u/benrimmington)\
**Post date:** [November 8, 2025, 1:40am UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/8 "2025-11-08T01:40:08Z")

</div>

> The `Span`, `MutableSpan`, and `InlineArray` types will conditionally conform to `ContiguousBytes` when the element type is `UInt8`, just like `Array` and `Unsafe(Mutable)BufferPointer` already do:

Should the new (and existing) conformances use `Element: BitwiseCopyable` instead? (`Trivial` is mentioned in some FIXME comments.)

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [November 8, 2025, 6:33am UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/9 "2025-11-08T06:33:07Z")

</div>

> [@jmschonfeld](#):
>
> ## Availability
> 
> Will these new declarations (either the requirement or the default implementation come with availability)? I assume the default implementation we can define as `@_alwaysEmitIntoClient` and therefore wouldn’t come with availability, but what about the protocol requirement - because the default implementation is always available will that not have availability either, or are there availability constraints on Darwin platforms to keep in mind for adoption here?

The protocol requirement needs to have availability constraints for the Swift 6.3 runtime (or wherever this lands), as do the new conformances of Span et al to `ContiguousBytes`. Everything else follows the availability of the types, i.e., Swift 6.2-aligned for `InlineArray` and Swift 5.1-aligned for the back-deployment targets of Span et al.

> [@jmschonfeld](#):
>
> ## `withUnsafeBytes` Typed Throws Adoption
> 
> Your implementation PR also updates the `ContiguousBytes.withUnsafeBytes` requirement to adopt typed throws, but I don’t think I see that mentioned in the proposal. Just to clarify, is that also a proposed change here, and are there any source or ABI compatibility impacts when doing so that we should be aware of?

The pull request only does this for Embedded Swift, where we need to use typed throws. I didn't think we needed to cover that in the proposal.

> [@jmschonfeld](#):
>
> ## `OutputSpan`
> 
> Should we also be adding a conformance to `Output(Raw)Span`? It’s simple enough to take an output span and call `.span` to get a `Span` which would conform, but the same argument can be said for types like `InlineArray` and `UTF8Span` which are gaining a conformance here, so would it be consistent to include `OutputSpan`?

I had forgotten that `OutputSpan` had a `span` property for the already-initialized values. I'll add it.

> [@glessard](#):
>
> I have a minor nit with the generic signature for `withBytes()` especially if it is to be codified in ABI: we should make sure that the order of the parameters in the angle brackets is the same as the order in the declaration. This has prevented us from updating the syntax of some stdlib functions to use anonymous generic types (`some Protocol`) in the past. I have no idea what syntax updates could occur here, but let’s not let this mistake occur again!

I don't think this applies to any of the generic parameters I've added; they all need to be referenced in multiple places and none of the protocols here have primary associated types.

> [@fclout](#):
>
> I imagine we have `withBytes` instead of a borrowing `bytes` property because we can’t have these yet in protocols?

It's also that some types that conform to `ContiguousBytes` couldn't provide a borrowing `bytes` property even if we could express it now. See the first section of Alternatives Considered for more.

> [@grynspan](#):
>
> I believe we should actually take this opportunity to move the protocol to the standard library. It is fundamentally valuable to be able to tell in advance if a particular sequence (or other value) has contiguous storage, which enables various fast paths. Having the protocol up in Foundation forces a dependency on a rather large library.

I agree that having to pull in `Foundation(Essentials)` to get this protocol and its conformances is a fairly heavy dependency. However, I think this protocol might be an evolutionary dead-end, and that more APIs should take `RawSpan` directly rather than a `ContiguousBytes`-conforming protocol.

> [@benrimmington](#):
>
> > The `Span`, `MutableSpan`, and `InlineArray` types will conditionally conform to `ContiguousBytes` when the element type is `UInt8`, just like `Array` and `Unsafe(Mutable)BufferPointer` already do:
> 
> Should the new (and existing) conformances use `Element: BitwiseCopyable` instead? (`Trivial` is mentioned in some FIXME comments.)

They can't, because `BitwiseCopyable` is a marker protocol and one cannot define a conditional conformance whose requirements involve a marker protocol (because we could not match them at runtime).

I suppose that the concrete `withBytes` I've been adding to all of these types could be use the more-general `BitwiseCopyable` constraint, although I don't know if that buys us all that much when the `span` property is right there.

Doug

---

<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:** [November 8, 2025, 2:00pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/10 "2025-11-08T14:00:17Z")

</div>

> [@Douglas\_Gregor](#):
>
> However, I think this protocol might be an evolutionary dead-end, and that more APIs should take `RawSpan` directly rather than a `ContiguousBytes`-conforming protocol.

Well, then why enhance it? 🙂

(On that note, is there a generic way to express “this type has a `bytes: RawSpan` or a `span: Span<Element>` property? Perhaps that's the protocol we need here?)

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [November 9, 2025, 6:40pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/11 "2025-11-09T18:40:10Z")

</div>

What happens if you conform a noncopyable type to this protocol and backwards deploy your program to an older Apple OS? It seems like that might result in weird behavior, and we cannot prevent that statically because we don’t yet have a way to express an availability requirement that says “this protocol has a `Self: Copyable` associated requirement before OS version N”.

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [November 9, 2025, 8:00pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/12 "2025-11-09T20:00:17Z")

</div>

> [@grynspan](#):
>
> > [@Douglas\_Gregor](#):
> >
> > However, I think this protocol might be an evolutionary dead-end, and that more APIs should take `RawSpan` directly rather than a `ContiguousBytes`-conforming protocol.
> 
> Well, then why enhance it? 🙂

Because some existing APIs are already using it, and it's easier to adopt Span if those APIs can be made to work with it in an ABI- and source-compatible way vs. introducing new ones. Maybe that's enough reason to sink it down into the standard library even in its somewhat-regrettable form.

> [@grynspan](#):
>
> (On that note, is there a generic way to express “this type has a `bytes: RawSpan` or a `span: Span<Element>` property? Perhaps that's the protocol we need here?)

We don't have a good way to do that yet. It's the API I would want a standard library protocol to provide.

> [@Slava\_Pestov](#):
>
> What happens if you conform a noncopyable type to this protocol and backwards deploy your program to an older Apple OS?

The only problematic scenario I know of is if you have an existing API in the system that uses `ContiguousBytes` and makes a copy of values of that type, then you generalize it with `@abi`:

```swift
@abi(func encrypt<Bytes: ContiguousBytes>(_ bytes: Bytes) -> [UInt8])
func encrypt<Bytes: ContiguousBytes>(_ bytes: Bytes) -> [UInt8] 
    where Bytes: ~Copyable, Bytes: ~Escapable {
 ... 
}

```

The safer thing to do, as an owner of an ABI-stable library like this, would be to keep the `Copyable` requirement but still generalize to `Bytes: ~Escapable`. You'll lose out on passing a `MutableSpan` directly into the API (it's `span` is okay), but it prevents any possibility of runtime issues. I'll update the discussion to capture this, thanks!

Doug

---

<div class="post-metadata">

**Author:** ![FranzBusch](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/franzbusch/32/19447_2.png) [@FranzBusch](https://forums.swift.org/u/FranzBusch)\
**Post date:** [November 10, 2025, 2:56pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/13 "2025-11-10T14:56:57Z")

</div>

> [@Douglas\_Gregor](#):
>
> However, I think this protocol might be an evolutionary dead-end, and that more APIs should take `RawSpan` directly rather than a `ContiguousBytes`-conforming protocol.

I wanted to raise exactly this question, so thanks for addressing this already. I was under the impression that `RawSpan` is our new currency type going forward, and APIs should start accepting that. It feels backwards if we expect new APIs to accept `ContiguousBytes` instead of `RawSpan`. However, I understand the motivation to make existing users of this protocol be able to re-spell their implementation on top of `RawSpan` than on top of unsafe pointers. Could we create a new API design guideline that recommends the usage of `RawSpan` and `Span<Element>` over using unsafe pointers or this protocol?

I have been working on a lot of asynchronous code recently that leverages spans, and one limitation of a lot of our new APIs is that they only provide the span in a synchronous closure, e.g. the new APIs that provide an `OutputSpan` on `InlineArray` or `Array`. This makes it impossible to compose with asynchronous code. Do we want to add an `async` variant for the proposed `RawSpan` API here as well?

> [@Douglas\_Gregor](#):
>
> The pull request only does this for Embedded Swift, where we need to use typed throws. I didn't think we needed to cover that in the proposal.

Why should we limit this to only Embedded? The thrown error is rethrown from the user provided closure. We have updated many APIs already throughout the stdlib and ecosystem to use typed throws in these cases since it makes composability with typed throws across the ecosystem easier and there is no downside such as locking in a concrete error type. If such a low-level protocol starts to provide dialects based on Embedded/non-Embedded it is going to grow the `#if` conditions throughout the ecosystem.

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [November 10, 2025, 4:55pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/15 "2025-11-10T16:55:38Z")

</div>

> [@FranzBusch](#):
>
> Could we create a new API design guideline that recommends the usage of `RawSpan` and `Span<Element>` over using unsafe pointers or this protocol?

This is a good idea. For the moment, I've added some documentation to `ContiguousBytes` into the PR for this change that nudges folks toward `RawSpan`. We'll need something more comprehensive for the API design guidelines.

> [@FranzBusch](#):
>
> Do we want to add an `async` variant for the proposed `RawSpan` API here as well?

The source-compatibility story for adding an `async` variant here isn't good, because you'd have to build it on top of the synchronous `withUnsafeBytes`.

> [@FranzBusch](#):
>
> Why should we limit this to only Embedded?

We don't know how to make this change to an existing protocol in a manner that maintains both source and binary compatibility. Embedded needs this change because it doesn't support untyped throws, and it's possible in Embedded because there's no ABI.

> [@FranzBusch](#):
>
> If such a low-level protocol starts to provide dialects based on Embedded/non-Embedded it is going to grow the `#if` conditions throughout the ecosystem.

The right answer here is to move to using `withBytes`, which is typed-throws everywhere and avoids this problem, while being safer.

Doug

---

<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:** [November 10, 2025, 7:36pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/16 "2025-11-10T19:36:38Z")

</div>

> [@FranzBusch](#):
>
> However, I understand the motivation to make existing users of this protocol be able to re-spell their implementation on top of `RawSpan` than on top of unsafe pointers. Could we create a new API design guideline that recommends the usage of `RawSpan` and `Span<Element>` over using unsafe pointers or this protocol?

It's tangential to this pitch, but I think the language needs a way to express "this protocol requirement is deprecated, use this one instead" that, at compile time, also automatically provides one or the other default implementations. Swift Testing has a similar problem that came up recently with its `Attachable` protocol taking an `UnsafeRawBufferPointer` instead of a `RawSpan`, but it's non-trivial to update the relevant protocol without either a) breaking existing adopters or b) having `withUnsafeBytes()` and `withBytes()` infinitely recurse through each other.

So I'm wondering if, for a pitch like this to succeed, we need a migration mechanism that isn't also a footgun.

**Edit:** None of my comments in this thread should be taken to mean we _shouldn't_ move folks to `RawSpan`, of course. 😃

---

<div class="post-metadata">

**Author:** ![bbrk24](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bbrk24/32/27370_2.png) [@bbrk24](https://forums.swift.org/u/bbrk24)\
**Post date:** [November 10, 2025, 9:52pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/17 "2025-11-10T21:52:25Z")

</div>

> [@grynspan](#):
>
> I think the language needs a way to express "this protocol requirement is deprecated, use this one instead" that, at compile time, also automatically provides one or the other default implementations.

So what's been special-cased for Hashable, but more general?

---

<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:** [November 10, 2025, 11:49pm UTC](https://forums.swift.org/t/pitch-generalize-contiguousbytes-to-support-span-et-al/83082/18 "2025-11-10T23:49:57Z")

</div>

You mean [this](https://github.com/swiftlang/swift/blob/a604d991d7bfe15606ed9b5c5fe0e57131205889/lib/Sema/DerivedConformance/DerivedConformanceEquatableHashable.cpp#L989)? Yeah, I'd like to be able to express that here too.
