SE-0488: Apply the `extracting()` slicing pattern more widely

Hello, Swift community!

The review of SE-0488: Apply the extracting() slicing pattern more widely begins now and runs through July 16th, 2025.

Reviews are an important part of the Swift evolution process. All review 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 put "SE-0488" in the subject line.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  • What is your evaluation of the proposal?
  • Is the problem being addressed significant enough to warrant a change to Swift?
  • Does this proposal fit well with the feel and direction of Swift?
  • If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  • How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at:

swift-evolution/process.md at main · swiftlang/swift-evolution · GitHub

Thank you,
Tony Allevato
Review Manager

5 Likes

I'm a bit disappointed at the added verbosity, given how much I use slicing in parsers, but I'm glad to see this coming!

Agree that the added verbosity is a bit disappointing, but generally +1.

Minor nitpick:

@available(*, unavailable, renamed: "extracting(first:)")
public func droppingFirst(_ k: Int) -> Self { extracting(first: k) }

should read

@available(*, unavailable, renamed: "extracting(droppingFirst:)")
public func droppingFirst(_ k: Int) -> Self { extracting(droppingFirst: k) }
3 Likes

The existing subscript [...] that takes an UnboundedRange is useful, because it returns a SubSequence. However, the extracting(...) method returns Self, so why is it needed?


The implementation for SE-0437 (Swift 6.0) simply returns a copy of self.

extension Unsafe${Mutable}BufferPointer where Element: ~Copyable {
  @safe
  public func extracting(_: UnboundedRange) -> Self {
    unsafe self
  }
}

The implementation for SE-0467 (Swift 6.2) is less trivial. I'm not sure what happens to _start() when the span is empty.

extension MutableSpan where Element: ~Copyable {
  @lifetime(&self)
  mutating public func extracting(_: UnboundedRange) -> Self {
    let newSpan = unsafe Self(_unchecked: _start(), count: _count)
    return unsafe _overrideLifetime(newSpan, mutating: &self)
  }
}
2 Likes

Overall, the proposal looks straightforward.

Could the new methods be made available on all subsequences? Since slicing a subsequence is a non-destructive action. I understand that they're redundant next to subscripts, but it leads into my second question.

Could the new methods be protocolized so I can say some Extractable<T> or similar?

2 Likes

The existing subscript [...] that takes an UnboundedRange is useful, because it returns a SubSequence. However, the extracting(...) method returns Self, so why is it needed?

When editing a line of code (especially in a playground-like situation,) it's convenient to be able to switch easily between different kinds of range expressions, and UnboundedRange is one of them. We shouldn't leave it out.

The implementation for SE-0467 (Swift 6.2) is less trivial. I'm not sure what happens to _start() when the span is empty.

Oh that's wrong. It should be _pointer. Thanks!
(Pull Request #82828.)

5 Likes

These methods may be part of the new Container protocol hierarchy, at which point they'd take their place on Collection.SubSequence types that also conform to Container. Right now I believe we can't do it because the associated types of protocols cannot be non-escapable (or non-copyable,) but this restriction will need to be remedied soon.

That's a fair enough reason not to do it, although frustrating—as I recall, that's a future direction on the ~Copyable proposal and is mostly implemented already, so it'd be nice to get it plumbed through so we could do such things.

Anyway, I'm off in the weeds here. Thanks for replying! :zipper_mouth_face:

1 Like

I've just realized that Slice.extracting(_:) with an UnboundedRange would be useful, if the indices of the new slice are rebased to zero.

1 Like

This proposal has been accepted.

1 Like