-
Notifications
You must be signed in to change notification settings - Fork 2.4k
[pitch] Apply the extracting()
slicing pattern to Span
& RawSpan
#2877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
glessard
wants to merge
12
commits into
swiftlang:main
Choose a base branch
from
glessard:extracting
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
d6f8cd4
initial pitch
glessard 54565a0
sanitize copy-pasted information
glessard a4b2002
add usage hints
glessard 38a77e9
improve opening graf of proposed solution
glessard 0113278
spelling and formatting
glessard 495f9be
formatting
glessard 0184b30
clarification
glessard 9a1371e
tweak title
glessard cc360dd
link to the proposal pull request
glessard fa3e8a4
fix from review comments
glessard 19c78ae
nit-picky wording change
glessard ba32f1a
Update proposals/nnnn-extracting.md
glessard File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
# Apply the extracting() slicing pattern more widely | ||
|
||
* Proposal: [TBD](https://github.com/swiftlang/swift-evolution/pull/2877) | ||
* Author: [Guillaume Lessard](https://github.com/glessard) | ||
* Review Manager: TBD | ||
* Status: **Pitch** | ||
* Implementation: underscored `_extracting()` members of `Span` and `RawSpan`, pending elsewhere. | ||
* Review: Pending | ||
|
||
[SE-0437]: proposals/0437-noncopyable-stdlib-primitives.md | ||
[SE-0447]: proposals/0447-span-access-shared-contiguous-storage.md | ||
[SE-0467]: proposals/0467-MutableSpan.md | ||
[Forum-LifetimeAnnotations]: https://forums.swift.org/t/78638 | ||
|
||
|
||
## Introduction and Motivation | ||
|
||
Slicing containers is an important operation, and non-copyable values have introduced a significant change in the spelling of that operation. When we [introduced][SE-0437] non-copyable primitives to the standard library, we allowed slicing `UnsafeBufferPointer` and related types via a family of `extracting()` methods. We expanded upon these when introducing [`MutableSpan`][SE-0467]. | ||
|
||
Now that we have a [stable spelling][Forum-LifetimeAnnotations] for lifetime dependencies, we propose adding the `extracting()` methods to `Span` and `RawSpan`, as well as members of the `UnsafeBufferPointer` family that were missed in [SE-0437][SE-0437]. | ||
|
||
|
||
## Proposed solution | ||
|
||
As previously discussed in [SE-0437][SE-0437], the slicing pattern established by the `Collection` protocol cannot be generalized for either non-copyable elements or non-escapable containers. The solution is a family of functions named `extracting()`, with appropriate argument labels. | ||
|
||
The family of `extracting()` methods established by the [`MutableSpan` proposal][SE-0467] is as follows: | ||
```swift | ||
public func extracting(_ bounds: Range<Index>) -> Self | ||
public func extracting(_ bounds: some RangeExpression<Index>) -> Self | ||
public func extracting(_: UnboundedRange) -> Self | ||
@unsafe public func extracting(unchecked bounds: Range<Index>) -> Self | ||
@unsafe public func extracting(unchecked bounds: ClosedRange<Index>) -> Self | ||
|
||
public func extracting(first maxLength: Int) -> Self | ||
public func extracting(droppingLast k: Int) -> Self | ||
public func extracting(last maxLength: Int) -> Self | ||
public func extracting(droppingFirst k: Int) -> Self | ||
``` | ||
|
||
These will be provided for the following standard library types: | ||
```swift | ||
Span<T> | ||
RawSpan | ||
UnsafeBufferPointer<T> | ||
UnsafeMutableBufferPointer<T> | ||
Slice<UnsafeBufferPointer<T>> | ||
Slice<UnsafeMutableBufferPointer<T>> | ||
UnsafeRawBufferPointer | ||
UnsafeMutableRawBufferPointer | ||
Slice<UnsafeRawBufferPointer> | ||
Slice<UnsafeMutableRawBufferPointer> | ||
``` | ||
Some of the types in the list above already have a subset of the `extracting()` functions; their support will be rounded out to the full set. | ||
|
||
|
||
## Detailed design | ||
|
||
The general declarations for these functions is as follows: | ||
```swift | ||
/// Returns an extracted slice over the items within | ||
/// the supplied range of positions. | ||
/// | ||
/// Traps if any position within the range is invalid. | ||
@_lifetime(copy self) | ||
public func extracting(_ byteOffsets: Range<Int>) -> Self | ||
glessard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Returns an extracted slice over the items within | ||
/// the supplied range of positions. | ||
/// | ||
/// Traps if any position within the range is invalid. | ||
@_lifetime(copy self) | ||
public func extracting(_ byteOffsets: some RangeExpression<Int>) -> Self | ||
|
||
/// Returns an extracted slice over all items of this container. | ||
@_lifetime(copy self) | ||
public func extracting(_: UnboundedRange) -> Self | ||
|
||
/// Returns an extracted slice over the items within | ||
/// the supplied range of positions. | ||
/// | ||
/// This function does not validate `bounds`; this is an unsafe operation. | ||
@unsafe @_lifetime(copy self) | ||
public func extracting(unchecked bounds: Range<Index>) -> Self | ||
|
||
/// Returns an extracted slice over the items within | ||
/// the supplied range of positions. | ||
/// | ||
/// This function does not validate `bounds`; this is an unsafe operation. | ||
@unsafe @_lifetime(copy self) | ||
public func extracting(unchecked bounds: ClosedRange<Index>) -> Self | ||
|
||
/// Returns an extracted slice over the initial elements | ||
/// of this container, up to the specified maximum length. | ||
@_lifetime(copy self) | ||
public func extracting(first maxLength: Int) -> Self | ||
|
||
/// Returns an extracted slice excluding | ||
/// the given number of trailing elements. | ||
@_lifetime(copy self) | ||
public func extracting(droppingLast k: Int) -> Self | ||
|
||
/// Returns an extracted slice containing the final elements | ||
/// of this container, up to the given maximum length. | ||
@_lifetime(copy self) | ||
public func extracting(last maxLength: Int) -> Self | ||
|
||
/// Returns an extracted slice excluding | ||
/// the given number of initial elements. | ||
@_lifetime(copy self) | ||
public func extracting(droppingFirst k: Int) -> Self | ||
``` | ||
For escapable types, the `@_lifetime` attribute is not applied. | ||
|
||
|
||
### Usage hints | ||
|
||
The `extracting()` pattern, while not completely new, is still a departure over the slice pattern established by the `Collection` protocol. For `Span`, `RawSpan`, `MutableSpan` and `MutableRawSpan`, we can add unavailable subscripts and function with hints towards the corresponding `extracting()` function: | ||
|
||
```swift | ||
@available(*, unavailable, renamed: "extracting(_ bounds:)") | ||
public subscript(bounds: Range<Index>) -> Self { extracting(bounds) } | ||
|
||
@available(*, unavailable, renamed: "extracting(first:)") | ||
public func droppingFirst(_ k: Int) -> Self { extracting(first: k) } | ||
``` | ||
|
||
## Source compatibility | ||
This proposal is additive and source-compatible with existing code. | ||
|
||
## ABI compatibility | ||
This proposal is additive and ABI-compatible with existing code. | ||
|
||
## Implications on adoption | ||
The additions described in this proposal require a new version of the Swift standard library. | ||
|
||
## Alternatives considered | ||
This is an extension of an existing pattern. We are not considering a different pattern at this time. | ||
|
||
## Future directions | ||
#### Disambiguation over ownership type | ||
The `extracting()` functions proposed here are borrowing. `MutableSpan` has versions defined as mutating, but it could benefit from consuming ones as well. In general there could be a need for all three ownership variants of a given operation (`borrowing`, `consuming`, or `mutating`.) In order to handle these variants, we could establish a pattern for disambiguation by name, or we could invent new syntax to disambiguate by ownership type. This is a complex topic left to future proposals. | ||
|
||
## Acknowledgements | ||
Thanks to Karoy Lorentey and Tony Parker. | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.