]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/language-features/unsized-locals.md
Remove a now-unnecessary paragraph.
[rust.git] / src / doc / unstable-book / src / language-features / unsized-locals.md
1 # `unsized_locals`
2
3 The tracking issue for this feature is: [#48055]
4
5 [#48055]: https://github.com/rust-lang/rust/issues/48055
6
7 ------------------------
8
9 This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
10
11 [RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-coercions.md
12
13 ```rust
14 #![feature(unsized_locals)]
15
16 use std::any::Any;
17
18 fn main() {
19     let x: Box<dyn Any> = Box::new(42);
20     let x: dyn Any = *x;
21     //  ^ unsized local variable
22     //               ^^ unsized temporary
23     foo(x);
24 }
25
26 fn foo(_: dyn Any) {}
27 //     ^^^^^^ unsized argument
28 ```
29
30 The RFC still forbids the following unsized expressions:
31
32 ```rust,ignore
33 #![feature(unsized_locals)]
34
35 use std::any::Any;
36
37 struct MyStruct<T: ?Sized> {
38     content: T,
39 }
40
41 struct MyTupleStruct<T: ?Sized>(T);
42
43 fn answer() -> Box<dyn Any> {
44     Box::new(42)
45 }
46
47 fn main() {
48     // You CANNOT have unsized statics.
49     static X: dyn Any = *answer();  // ERROR
50     const Y: dyn Any = *answer();  // ERROR
51
52     // You CANNOT have struct initialized unsized.
53     MyStruct { content: *answer() };  // ERROR
54     MyTupleStruct(*answer());  // ERROR
55     (42, *answer());  // ERROR
56
57     // You CANNOT have unsized return types.
58     fn my_function() -> dyn Any { *answer() }  // ERROR
59
60     // You CAN have unsized local variables...
61     let mut x: dyn Any = *answer();  // OK
62     // ...but you CANNOT reassign to them.
63     x = *answer();  // ERROR
64
65     // You CANNOT even initialize them separately.
66     let y: dyn Any;  // OK
67     y = *answer();  // ERROR
68
69     // Not mentioned in the RFC, but by-move captured variables are also Sized.
70     let x: dyn Any = *answer();
71     (move || {  // ERROR
72         let y = x;
73     })();
74
75     // You CAN create a closure with unsized arguments,
76     // but you CANNOT call it.
77     // This is an implementation detail and may be changed in the future.
78     let f = |x: dyn Any| {};
79     f(*answer());  // ERROR
80 }
81 ```
82
83 However, the current implementation allows `MyTupleStruct(..)` to be unsized. This will be fixed in the future.
84
85 ## By-value trait objects
86
87 With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
88
89 ```rust
90 #![feature(unsized_locals)]
91
92 trait Foo {
93     fn foo(self) {}
94 }
95
96 impl<T: ?Sized> Foo for T {}
97
98 fn main() {
99     let slice: Box<[i32]> = Box::new([1, 2, 3]);
100     <[i32] as Foo>::foo(*slice);
101 }
102 ```
103
104 And `Foo` will also be object-safe. However, this object-safety is not yet implemented.
105
106 ```rust,ignore
107 #![feature(unsized_locals)]
108
109 trait Foo {
110     fn foo(self) {}
111 }
112
113 impl<T: ?Sized> Foo for T {}
114
115 fn main () {
116     let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
117     // doesn't compile yet
118     <dyn Foo as Foo>::foo(*slice);
119 }
120 ```
121
122 Unfortunately, this is not implemented yet.
123
124 One of the objectives of this feature is to allow `Box<dyn FnOnce>`, instead of `Box<dyn FnBox>` in the future. See [#28796] for details.
125
126 [#28796]: https://github.com/rust-lang/rust/issues/28796
127
128 ## Variable length arrays
129
130 The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.
131
132 ```rust,ignore
133 #![feature(unsized_locals)]
134
135 fn mergesort<T: Ord>(a: &mut [T]) {
136     let mut tmp = [T; dyn a.len()];
137     // ...
138 }
139
140 fn main() {
141     let mut a = [3, 1, 5, 6];
142     mergesort(&mut a);
143     assert_eq!(a, [1, 3, 5, 6]);
144 }
145 ```
146
147 VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.
148
149 ## Advisory on stack usage
150
151 It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:
152
153 - When you need a by-value trait objects.
154 - When you really need a fast allocation of small temporary arrays.
155
156 Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code
157
158 ```rust
159 #![feature(unsized_locals)]
160
161 fn main() {
162     let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
163     let _x = {{{{{{{{{{*x}}}}}}}}}};
164 }
165 ```
166
167 and the code
168
169 ```rust
170 #![feature(unsized_locals)]
171
172 fn main() {
173     for _ in 0..10 {
174         let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
175         let _x = *x;
176     }
177 }
178 ```
179
180 will unnecessarily extend the stack frame.