[Review] SF-0042 Data Manipulation with Spans

Hello Swift community,

We are seeking feedback on Data Manipulation with Spans through 2026-07-28.

Your feedback is an important part of the Swift-Foundation evolution process. All feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager by DM. When contacting the review manager directly, please include the proposal name in the subject line.

Things to consider

The goal of this feedback period is to improve the proposal through constructive discussion. Here are some questions to consider in your feedback:

  • How much effort did you put into your evaluation of this proposal?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

More information about Swift-Foundation evolution process is available at

swift-foundation/CONTRIBUTING.md at main · swiftlang/swift-foundation · GitHub

And if you like this proposal, please don't be shy to express your positive support, with a heart or a word of encouragement.

Thank you,

Tina, Review Manager

6 Likes

This API looks like a great addition to me.

One question:

public init(
        capacity: Int? = nil,
        copying span: RawSpan
    )

What's the behavior if capacity is < span.count? Does it copy a subset of span, assert, something else?

For a stdlib API like this, we would generally make capacity >= span.count a precondition. Foundation doesn't have to follow that, but I think it probably makes sense here.

I think the other alternative I could see would be change the spelling to:

init(copying: RawSpan, minimumCapacity: Int? = nil)

and make it always copy the full span into a buffer of size max(span.count, minimumCapacity).

1 Like

This is an interesting question. My original intent was to follow UniqueArray's behavior which is to precondition that capacity >= span.byteCount - the documentation on the API mentions this. I almost replied that I think we should persist this behavior and any extending of capacity should be a separate minimumCapacity: initializer like Steve mentioned.

However, it is possible that Data and UniqueArray may differ in semantics when it comes to rounding of capacity. For example, the existing Data.init(capacity:) does allocate more than capacity bytes in some circumstances and is documented as such:

If the capacity specified in `capacity` is greater than four memory pages in size, this may round the amount of requested memory up to the nearest full page.

That naturally begs the question whether the precondition should happen before or after said rounding. Does UniqueArray have similar rounding behavior, or does it always allocate the exact number of bytes provided?

Does Data do the rounding itself or does it let the underlying allocator do it?

Data does the rounding itself:

Since Foundation tries to present a portable abstraction, we'd want the precondition to be enforced before rounding. Otherwise people could write code that works on, say, macOS/arm64 and it would crash when used on a system with a smaller page size.

That's a good point, so based on that it seems reasonable to me that Data can maintain the same behavior as UniqueArray for this API (precondition(capacity >= span.byteCount) and that there could be a future direction (if desired) to introduce a separate init(minimumCapacity:copying:) that all container types would also implement in addition to this one (for consistency among the types in behavior here)

1 Like

I have no reason to object this proposal, but let me nitpick...

the previously-approved Data(rawCapacity:initializingWith:) and Data.append(addingRawCapacity:initializingWith:)APIs

I think this means SE-0485, whereas I couldn't find the link to it.
I leave this comment just for the record.

2 Likes

Hi community,

The review concluded on July 28.

The only review feedback from the workgroup is that we'd like to ask Jeremy to clarify the precondition in the implementation and header docs. Other than that, the Foundation workgroup has happily accepted this proposal.

Thanks.

3 Likes

Hi Tina,

I put moderate effort into evaluating the proposal by reviewing the API surface and testing a few local prototypes.

Coming from Rust (&[T] / &mut [T]) and C#, I think this proposal strikes the right balance between memory safety and low-overhead data manipulation. It fills a crucial gap for performance-sensitive tasks in Swift without sacrificing language ergonomics.

Fully supportive of this addition to Swift-Foundation!