|
| 1 | +- Feature Name: array-trait |
| 2 | +- Start Date: 2017-02-21 |
| 3 | +- RFC PR: |
| 4 | +- Rust Issue: |
| 5 | + |
| 6 | +# Summary |
| 7 | +[summary]: #summary |
| 8 | + |
| 9 | +Extend and stabilize the `FixedSizeArray` trait, |
| 10 | +as a stop-gap solution for integer parameters in generics. |
| 11 | + |
| 12 | + |
| 13 | +# Motivation |
| 14 | +[motivation]: #motivation |
| 15 | + |
| 16 | +One of Rust’s basic families of types is fixed-size arrays: |
| 17 | +`[T; N]` where `T` is any (statically-sized) type, and `N` is an (`usize`) integer. |
| 18 | +Arrays with the same `T` item type but of different sizes are themselves different types. |
| 19 | + |
| 20 | +A [long-standing](https://github.com/rust-lang/rfcs/pull/884) |
| 21 | +feature [request](https://github.com/rust-lang/rfcs/issues/1038) |
| 22 | +it the ability to write code that is generic over the size of an array. |
| 23 | +The solution typically proposed for this it “type-level integers”, |
| 24 | +where generic items can have integers as a new *kind* of type-level parameters, |
| 25 | +in addition to lifetime parameters and type parameters. |
| 26 | + |
| 27 | +This by itself introduce it’s share of complexity. |
| 28 | +Even so, such proposals are often extended to cover arbitrary type levels (not just integers), |
| 29 | +or even dependent types. |
| 30 | +As a result, every RFC on the subject so far has been postponed: |
| 31 | +[1](https://github.com/rust-lang/rfcs/pull/884), |
| 32 | +[2](https://github.com/rust-lang/rfcs/pull/1062), |
| 33 | +[3](https://github.com/rust-lang/rfcs/pull/1520), |
| 34 | +[4](https://github.com/rust-lang/rfcs/issues/1557), |
| 35 | +[5](https://github.com/rust-lang/rfcs/pull/1657). |
| 36 | + |
| 37 | +This RFC propose an addition to the language that, |
| 38 | +although less theoretically pleasing, |
| 39 | +is much smaller and therefore hopefully more likely to be accepted. |
| 40 | +Additionally, it does not prevent a more general solution from also happening in the future. |
| 41 | + |
| 42 | +Arrays are the only case where integers occur in types, in current Rust. |
| 43 | +Therefore a solution specifically for arrays |
| 44 | +covers many (most? all?) of the use cases for type-level integers. |
| 45 | + |
| 46 | + |
| 47 | +# Detailed design |
| 48 | +[design]: #detailed-design |
| 49 | + |
| 50 | +The `core::array` module currently contains a `FixedSizeArray` trait. |
| 51 | +Both are unstable. |
| 52 | +This RFC proposes three changes: |
| 53 | + |
| 54 | +* Extend the `FixedSizeArray`. (This is optional, see alternatives.) |
| 55 | +* Reexport the module as `std::array`. |
| 56 | +* Stabilize both the module an the trait. |
| 57 | + |
| 58 | +The current definition of the trait is: |
| 59 | + |
| 60 | +```rust |
| 61 | +pub unsafe trait FixedSizeArray<T> { |
| 62 | + /// Converts the array to immutable slice |
| 63 | + fn as_slice(&self) -> &[T]; |
| 64 | + /// Converts the array to mutable slice |
| 65 | + fn as_mut_slice(&mut self) -> &mut [T]; |
| 66 | +} |
| 67 | + |
| 68 | +unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A { |
| 69 | + #[inline] |
| 70 | + fn as_slice(&self) -> &[T] { |
| 71 | + self |
| 72 | + } |
| 73 | + #[inline] |
| 74 | + fn as_mut_slice(&mut self) -> &mut [T] { |
| 75 | + self |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +A single `impl` applies to array of all sizes, thanks to the `Unsize` trait. |
| 81 | +That trait is also unstable. |
| 82 | +It exists to support for [DST coercions](https://github.com/rust-lang/rust/issues/27732), |
| 83 | +itself a somewhat complex feature that might take some time to stabilize. |
| 84 | + |
| 85 | +This trait is already useful as-is, |
| 86 | +but it would be nice to extend it to include the array’s length and item type |
| 87 | +as an associated constant |
| 88 | +and an associated type (which replaces the type parameter): |
| 89 | + |
| 90 | +```rust |
| 91 | +pub unsafe trait FixedSizeArray { |
| 92 | + // Added: |
| 93 | + type Item; |
| 94 | + const LENGTH: usize; |
| 95 | + |
| 96 | + // Unchanged: |
| 97 | + fn as_slice(&self) -> &[Self::Item]; |
| 98 | + fn as_mut_slice(&mut self) -> &mut [Self::Item]; |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +However these can not be provided by in `impl` based on `Unsize<[T]>` like the current one. |
| 103 | +Instead, this RFC proposes that all array types implement the trait through “compiler magic”. |
| 104 | +There would be no corresponding `impl` block in libcore or other library crates, |
| 105 | +the existence of these implementations would be part of the definition of the Rust language. |
| 106 | +There is precedent for such “magic” implementations in the language of other traits: |
| 107 | + |
| 108 | +* `Unsize` |
| 109 | +* `Sized` |
| 110 | +* `Fn`, `FnMut`, `FnMove` (for closures types, which are very magical themselves) |
| 111 | +* `Copy`, `Drop` (not implemented implicitly, but `impl`s have “magical” requirements) |
| 112 | + |
| 113 | + |
| 114 | +# How We Teach This |
| 115 | +[how-we-teach-this]: #how-we-teach-this |
| 116 | + |
| 117 | +The `array` module and `FixedSizeArray` trait already have rustdoc documentation |
| 118 | +that seems appropriate. |
| 119 | + |
| 120 | +The trait could be mentioned in the *Primitive Types* or *Generics* chapter of the book. |
| 121 | + |
| 122 | + |
| 123 | +# Drawbacks |
| 124 | +[drawbacks]: #drawbacks |
| 125 | + |
| 126 | +Doing this “shouldn’t” be necessary if we assume that Rust is going to have |
| 127 | +type-level integers / type-level constants / dependent types (take your pick) eventually. |
| 128 | +However, shipping imperfect features are arguably superior to |
| 129 | +“better” features that haven’t been happening for several years already |
| 130 | +with no significant progress in sight. |
| 131 | + |
| 132 | + |
| 133 | +# Alternatives |
| 134 | +[alternatives]: #alternatives |
| 135 | + |
| 136 | +* Stabilize the `FixedSizeArray` trait as-is |
| 137 | + (without an associated type or associated constant, with a type parameter). |
| 138 | + |
| 139 | +* Figure out type-level integers, and deprecate / remove the `FixedSizeArray` trait. |
| 140 | + |
| 141 | + |
| 142 | +# Unresolved questions |
| 143 | +[unresolved]: #unresolved-questions |
| 144 | + |
| 145 | +* To extend or not to extend. (See [Alternatives](#alternatives).) |
| 146 | + |
| 147 | +* Should the compiler prevent other implementations of the trait? |
| 148 | + There is precedent for that with the `Unsize` trait and error number E0328. |
| 149 | + |
| 150 | +* Rename `FixedSizeArray` to `Array`? |
| 151 | + All arrays in Rust are fixed-size. |
| 152 | + The things similar to arrays that are not fixed-size are called slices or vectors. |
0 commit comments