-
Notifications
You must be signed in to change notification settings - Fork 1.6k
RFC: Extend and stabilize the FixedSizeArray trait #1915
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
Closed
Closed
Changes from all commits
Commits
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 @@ | ||
- Feature Name: array-trait | ||
- Start Date: 2017-02-21 | ||
- RFC PR: | ||
- Rust Issue: | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Extend and stabilize the `FixedSizeArray` trait, | ||
as a stop-gap solution for integer parameters in generics. | ||
|
||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
One of Rust’s basic families of types is fixed-size arrays: | ||
`[T; N]` where `T` is any (statically-sized) type, and `N` is an (`usize`) integer. | ||
Arrays with the same `T` item type but of different sizes are themselves different types. | ||
|
||
A [long-standing](https://github.com/rust-lang/rfcs/pull/884) | ||
feature [request](https://github.com/rust-lang/rfcs/issues/1038) | ||
it the ability to write code that is generic over the size of an array. | ||
The solution typically proposed for this it “type-level integers”, | ||
where generic items can have integers as a new *kind* of type-level parameters, | ||
in addition to lifetime parameters and type parameters. | ||
|
||
However, every RFC on the subject so far has been postponed: | ||
[1](https://github.com/rust-lang/rfcs/pull/884), | ||
[2](https://github.com/rust-lang/rfcs/pull/1062), | ||
[3](https://github.com/rust-lang/rfcs/pull/1520), | ||
[4](https://github.com/rust-lang/rfcs/issues/1557), | ||
[5](https://github.com/rust-lang/rfcs/pull/1657). | ||
|
||
This RFC propose an addition to the language that, | ||
although less theoretically pleasing, | ||
is much smaller and therefore hopefully more likely to be accepted. | ||
Additionally, it does not prevent a more general solution from also happening in the future. | ||
|
||
Arrays are the only case where integers occur in types, in current Rust. | ||
Therefore a solution specifically for arrays | ||
hopefully covers many of the use cases for type-level integers. | ||
|
||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
The `core::array` module currently contains a `FixedSizeArray` trait. | ||
Both are unstable. | ||
This RFC proposes three changes: | ||
|
||
* Extend the `FixedSizeArray`. (This is optional, see alternatives.) | ||
* Reexport the module as `std::array`. | ||
* Stabilize both the module an the trait. | ||
|
||
The current definition of the trait is: | ||
|
||
```rust | ||
pub unsafe trait FixedSizeArray<T> { | ||
/// Converts the array to immutable slice | ||
fn as_slice(&self) -> &[T]; | ||
/// Converts the array to mutable slice | ||
fn as_mut_slice(&mut self) -> &mut [T]; | ||
} | ||
|
||
unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A { | ||
#[inline] | ||
fn as_slice(&self) -> &[T] { | ||
self | ||
} | ||
#[inline] | ||
fn as_mut_slice(&mut self) -> &mut [T] { | ||
self | ||
} | ||
} | ||
``` | ||
|
||
A single `impl` applies to array of all sizes, thanks to the `Unsize` trait. | ||
That trait is also unstable. | ||
It exists to support for [DST coercions](https://github.com/rust-lang/rust/issues/27732), | ||
itself a somewhat complex feature that might take some time to stabilize. | ||
|
||
This trait is already useful as-is, | ||
but it would be nice to extend it to include the array’s length and item type | ||
as an associated constant | ||
and an associated type (which replaces the type parameter): | ||
|
||
```rust | ||
pub unsafe trait FixedSizeArray { | ||
// Added: | ||
type Item; | ||
const LENGTH: usize; | ||
|
||
// Unchanged: | ||
fn as_slice(&self) -> &[Self::Item]; | ||
fn as_mut_slice(&mut self) -> &mut [Self::Item]; | ||
} | ||
``` | ||
|
||
However these can not be provided by in `impl` based on `Unsize<[T]>` like the current one. | ||
Instead, this RFC proposes that all array types implement the trait through “compiler magic”. | ||
There would be no corresponding `impl` block in libcore or other library crates, | ||
the existence of these implementations would be part of the definition of the Rust language. | ||
There is precedent for such “magic” implementations in the language of other traits: | ||
|
||
* `Unsize` | ||
* `Sized` | ||
* `Fn`, `FnMut`, `FnMove` (for closures types, which are very magical themselves) | ||
* `Copy`, `Drop` (not implemented implicitly, but `impl`s have “magical” requirements) | ||
|
||
|
||
# How We Teach This | ||
[how-we-teach-this]: #how-we-teach-this | ||
|
||
The `array` module and `FixedSizeArray` trait already have rustdoc documentation | ||
that seems appropriate. | ||
|
||
The trait could be mentioned in the *Primitive Types* or *Generics* chapter of the book. | ||
|
||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
This an ad-hoc work-around for something that could be solved with a more general mechanism | ||
in the future. | ||
|
||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
* Stabilize the `FixedSizeArray` trait as-is | ||
(without an associated type or associated constant, with a type parameter). | ||
|
||
* Figure out type-level integers, and deprecate / remove the `FixedSizeArray` trait. | ||
|
||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
* To extend or not to extend. (See [Alternatives](#alternatives).) | ||
|
||
* Should the compiler prevent other implementations of the trait? | ||
There is precedent for that with the `Unsize` trait and error number E0328. | ||
|
||
* Rename `FixedSizeArray` to `Array`? | ||
All arrays in Rust are fixed-size. | ||
The things similar to arrays that are not fixed-size are called slices or vectors. |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just handling arrays doesn't enable things like C++'s std::chrono, so it's definitely not "all". Maybe scope the claim to "std's current trait implementations for arrays" or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain what C++’s
std::chrono
is and how it relates to arrays?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On re-reading you comment it sounds like it doesn’t involve arrays, but it might involve type-level integers? Yes, this RFC does not entirely remove the need for type-level integers, but it doesn’t prevent adding them later either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, apparently I put this comment on a poor choice of line; I thought it had the next one in the context too.
I agree with your comment, just think the motivation is over-selling itself by talking about covering "many (all?) of the use cases for type-level integers". Probably an ignorable nitpick.
Hmm, are associated constants
const
enough to be used in type checking? Would this enablefn pop_array<T:Array>(x : T) -> [T::Item; T::LENGTH - 1] { ... }
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I asked this up thread and @eddyb answered : #1915 (comment) This now works when
T
is some fixed type, but it does not yet work ifT
is a type parameter like in your question.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where "now" is whenever rust-lang/rust#40008 gets merged.