Skip to content

Commit 577ed56

Browse files
committed
rfc, const_repeat_expr: initial version
1 parent bc430eb commit 577ed56

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

text/0000-const-repeat-expr.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
- Feature Name: const_repeat_expr
2+
- Start Date: 2017-10-20
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Relaxes the rules for repeat expressions, `[x; N]` such that `x` may also be
10+
`const`, in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is
11+
`const` is itself also `const`.
12+
13+
# Motivation
14+
[motivation]: #motivation
15+
16+
[RFC 2000, `const_generics`]: https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md
17+
[`const_default` RFC]: https://github.com/Centril/rfcs/blob/rfc/const-default/text/0000-const-default.md
18+
19+
[RFC 2000, `const_generics`] introduced the ability to have generically sized
20+
arrays. Even with that RFC, it is currently impossible to create such an array
21+
that is also `const`. Creating an array that is `const` may for example be
22+
useful for the [`const_default` RFC] which proposes the following trait:
23+
24+
```rust
25+
pub trait ConstDefault { const DEFAULT: Self; }
26+
```
27+
28+
To add an implementation of this trait for an array of any size where the
29+
elements of type `T` are `ConstDefault`, as in:
30+
31+
```rust
32+
impl<T: ConstDefault, const N: usize> ConstDefault for [T; N] {
33+
const DEFAULT: Self = [T::DEFAULT; N];
34+
}
35+
```
36+
37+
[`std::mem::uninitialized()`]: https://doc.rust-lang.org/nightly/std/mem/fn.uninitialized.html
38+
39+
In the example given by [`std::mem::uninitialized()`], a value of type
40+
`[Vec<u32>; 1000]` is created and filled. With this RFC, and when `Vec::new()`
41+
becomes const, the user can simply write:
42+
43+
```rust
44+
let data = [Vec::<u32>::new(); 1000];
45+
println!("{:?}", &data[0]);
46+
```
47+
48+
this removes one common reason to use `uninitialized()` which **"is incredibly
49+
dangerous"**.
50+
51+
# Guide-level explanation
52+
[guide-level-explanation]: #guide-level-explanation
53+
54+
You have a variable or expression `X` which is const, for example:
55+
56+
```rust
57+
type T = Option<Box<u32>>;
58+
const X: T = None;
59+
```
60+
61+
Now, you'd like to use array repeat expressions `[X; N]` to create an array
62+
containing a bunch of `X`es. Sorry, you are out of luck!
63+
64+
But with this RFC, you can now write:
65+
66+
```rust
67+
const X: T = None;
68+
const arr: [u32; 100] = [X; 100];
69+
```
70+
71+
or, if you wish to modify the array later:
72+
73+
```rust
74+
const X: T = None;
75+
let mut arr = [x; 100];
76+
arr[0] = Some(Box::new(1));
77+
```
78+
79+
# Reference-level explanation
80+
[reference-level-explanation]: #reference-level-explanation
81+
82+
Values which are `const` are freely duplicatable as seen in the following
83+
example which compiles today. This is also the case with `Copy`. Therefore, the
84+
value `X` in the repeat expression may be simply treated as if it were of a
85+
`Copy` type.
86+
87+
```rust
88+
fn main() {
89+
type T = Option<Box<u32>>;
90+
const X: T = None;
91+
let mut arr = [X, X];
92+
arr[0] = Some(Box::new(1));
93+
}
94+
```
95+
96+
Thus, the compiler may rewrite this internally as:
97+
98+
```rust
99+
// This is the value to be repeated and typeof(X) the type it has.
100+
const X: typeof(X) = VALUE;
101+
// N is the size of the array and how many times to repeat X.
102+
const N: usize = SIZE;
103+
104+
{
105+
let mut data: [typeof(X); N];
106+
107+
unsafe {
108+
data = mem::uninitialized();
109+
110+
let mut iter = (&mut data[..]).into_iter();
111+
while let Some(elem) = iter.next() {
112+
// ptr::write does not run destructor of elem already in array.
113+
// Since X is const, it can not panic.
114+
ptr::write(elem, X);
115+
}
116+
}
117+
118+
data
119+
}
120+
```
121+
122+
Additionally, the pass that checks `const`ness must treat `[X; N]` as a `const`
123+
value.
124+
125+
# Drawbacks
126+
[drawbacks]: #drawbacks
127+
128+
It might make the semantics of array initializers more fuzzy. The RFC, however,
129+
argues that the change is quite intuitive.
130+
131+
# Rationale and alternatives
132+
[alternatives]: #alternatives
133+
134+
[`ptr::write(..)`]: https://doc.rust-lang.org/nightly/std/ptr/fn.write.html
135+
136+
The alternative, in addition to simply not doing this, is to modify a host of
137+
other constructs such as [`std::mem::uninitialized()`], for loops over iterators,
138+
[`ptr::write`] to be `const`, which is is a larger change. The design offered by
139+
this RFC is therefore the simplest and most non-intrusive design. It is also
140+
the most consistent.
141+
142+
The impact of not doing this change is to not enable generically sized arrays to
143+
be `const`.
144+
145+
# Unresolved questions
146+
[unresolved]: #unresolved-questions
147+
148+
[`drop_types_in_const`]: https://github.com/rust-lang/rfcs/blob/master/text/1440-drop-types-in-const.md
149+
150+
The relation to [`drop_types_in_const`] should be resolved during the RFC process.
151+
The soundness of the proposal should be verified.
152+
Other than that, there are no unresolved questions.

0 commit comments

Comments
 (0)