|
1 | 1 | % The Rust Design FAQ
|
2 | 2 |
|
3 |
| -This document describes decisions that were arrived at after lengthy discussion and |
4 |
| -experimenting with alternatives. Please do not propose reversing them unless |
5 |
| -you have a new, extremely compelling argument. Note that this document |
6 |
| -specifically talks about the *language* and not any library or implementation. |
7 |
| - |
8 |
| -A few general guidelines define the philosophy: |
9 |
| - |
10 |
| -- [Memory safety][mem] must never be compromised |
11 |
| -- [Abstraction][abs] should be zero-cost, while still maintaining safety |
12 |
| -- Practicality is key |
13 |
| - |
14 |
| -[mem]: http://en.wikipedia.org/wiki/Memory_safety |
15 |
| -[abs]: http://en.wikipedia.org/wiki/Abstraction_%28computer_science%29 |
16 |
| - |
17 |
| -# Semantics |
18 |
| - |
19 |
| -## Data layout is unspecified |
20 |
| - |
21 |
| -In the general case, `enum` and `struct` layout is undefined. This allows the |
22 |
| -compiler to potentially do optimizations like re-using padding for the |
23 |
| -discriminant, compacting variants of nested enums, reordering fields to remove |
24 |
| -padding, etc. `enum`s which carry no data ("C-like") are eligible to have a |
25 |
| -defined representation. Such `enum`s are easily distinguished in that they are |
26 |
| -simply a list of names that carry no data: |
27 |
| - |
28 |
| -``` |
29 |
| -enum CLike { |
30 |
| - A, |
31 |
| - B = 32, |
32 |
| - C = 34, |
33 |
| - D |
34 |
| -} |
35 |
| -``` |
36 |
| - |
37 |
| -The [repr attribute][repr] can be applied to such `enum`s to give them the same |
38 |
| -representation as a primitive. This allows using Rust `enum`s in FFI where C |
39 |
| -`enum`s are also used, for most use cases. The attribute can also be applied |
40 |
| -to `struct`s to get the same layout as a C struct would. |
41 |
| - |
42 |
| -[repr]: reference.html#ffi-attributes |
43 |
| - |
44 |
| -## There is no GC |
45 |
| - |
46 |
| -A language that requires a GC is a language that opts into a larger, more |
47 |
| -complex runtime than Rust cares for. Rust is usable on bare metal with no |
48 |
| -extra runtime. Additionally, garbage collection is frequently a source of |
49 |
| -non-deterministic behavior. Rust provides the tools to make using a GC |
50 |
| -possible and even pleasant, but it should not be a requirement for |
51 |
| -implementing the language. |
52 |
| - |
53 |
| -## Non-`Sync` `static mut` is unsafe |
54 |
| - |
55 |
| -Types which are [`Sync`][sync] are thread-safe when multiple shared |
56 |
| -references to them are used concurrently. Types which are not `Sync` are not |
57 |
| -thread-safe, and thus when used in a global require unsafe code to use. |
58 |
| - |
59 |
| -[sync]: core/marker/trait.Sync.html |
60 |
| - |
61 |
| -### If mutable static items that implement `Sync` are safe, why is taking &mut SHARABLE unsafe? |
62 |
| - |
63 |
| -Having multiple aliasing `&mut T`s is never allowed. Due to the nature of |
64 |
| -globals, the borrow checker cannot possibly ensure that a static obeys the |
65 |
| -borrowing rules, so taking a mutable reference to a static is always unsafe. |
66 |
| - |
67 |
| -## There is no life before or after main (no static ctors/dtors) |
68 |
| - |
69 |
| -Globals can not have a non-constant-expression constructor and cannot have a |
70 |
| -destructor at all. This is an opinion of the language. Static constructors are |
71 |
| -undesirable because they can slow down program startup. Life before main is |
72 |
| -often considered a misfeature, never to be used. Rust helps this along by just |
73 |
| -not having the feature. |
74 |
| - |
75 |
| -See [the C++ FQA][fqa] about the "static initialization order fiasco", and |
76 |
| -[Eric Lippert's blog][elp] for the challenges in C#, which also has this |
77 |
| -feature. |
78 |
| - |
79 |
| -A nice replacement is [lazy_static][lazy_static]. |
80 |
| - |
81 |
| -[fqa]: http://yosefk.com/c++fqa/ctors.html#fqa-10.12 |
82 |
| -[elp]: http://ericlippert.com/2013/02/06/static-constructors-part-one/ |
83 |
| -[lazy_static]: https://crates.io/crates/lazy_static |
84 |
| - |
85 |
| -## The language does not require a runtime |
86 |
| - |
87 |
| -See the above entry on GC. Requiring a runtime limits the utility of the |
88 |
| -language, and makes it undeserving of the title "systems language". All Rust |
89 |
| -code should need to run is a stack. |
90 |
| - |
91 |
| -## `match` must be exhaustive |
92 |
| - |
93 |
| -`match` being exhaustive has some useful properties. First, if every |
94 |
| -possibility is covered by the `match`, adding further variants to the `enum` |
95 |
| -in the future will prompt a compilation failure, rather than runtime panic. |
96 |
| -Second, it makes cost explicit. In general, the only safe way to have a |
97 |
| -non-exhaustive match would be to panic the thread if nothing is matched, though |
98 |
| -it could fall through if the type of the `match` expression is `()`. This sort |
99 |
| -of hidden cost and special casing is against the language's philosophy. It's |
100 |
| -easy to ignore all unspecified cases by using the `_` wildcard: |
101 |
| - |
102 |
| -```rust,ignore |
103 |
| -match val.do_something() { |
104 |
| - Cat(a) => { /* ... */ } |
105 |
| - _ => { /* ... */ } |
106 |
| -} |
107 |
| -``` |
108 |
| - |
109 |
| -[#3101][iss] is the issue that proposed making this the only behavior, with |
110 |
| -rationale and discussion. |
111 |
| - |
112 |
| -[iss]: https://github.com/rust-lang/rust/issues/3101 |
113 |
| - |
114 |
| -## No guaranteed tail-call optimization |
115 |
| - |
116 |
| -In general, tail-call optimization is not guaranteed: see [here][tml] for a |
117 |
| -detailed explanation with references. There is a [proposed extension][tce] that |
118 |
| -would allow tail-call elimination in certain contexts. The compiler is still |
119 |
| -free to optimize tail-calls [when it pleases][sco], however. |
120 |
| - |
121 |
| -[tml]: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html |
122 |
| -[sco]: http://llvm.org/docs/CodeGenerator.html#sibling-call-optimization |
123 |
| -[tce]: https://github.com/rust-lang/rfcs/pull/81 |
124 |
| - |
125 |
| -## No constructors |
126 |
| - |
127 |
| -Functions can serve the same purpose as constructors without adding any |
128 |
| -language complexity. |
129 |
| - |
130 |
| -## No copy constructors |
131 |
| - |
132 |
| -Types which implement [`Copy`][copy], will do a standard C-like "shallow copy" |
133 |
| -with no extra work (similar to "plain old data" in C++). It is impossible to |
134 |
| -implement `Copy` types that require custom copy behavior. Instead, in Rust |
135 |
| -"copy constructors" are created by implementing the [`Clone`][clone] trait, |
136 |
| -and explicitly calling the `clone` method. Making user-defined copy operators |
137 |
| -explicit surfaces the underlying complexity, forcing the developer to opt-in |
138 |
| -to potentially expensive operations. |
139 |
| - |
140 |
| -[copy]: core/marker/trait.Copy.html |
141 |
| -[clone]: core/clone/trait.Clone.html |
142 |
| - |
143 |
| -## No move constructors |
144 |
| - |
145 |
| -Values of all types are moved via `memcpy`. This makes writing generic unsafe |
146 |
| -code much simpler since assignment, passing and returning are known to never |
147 |
| -have a side effect like unwinding. |
148 |
| - |
149 |
| -# Syntax |
150 |
| - |
151 |
| -## Macros require balanced delimiters |
152 |
| - |
153 |
| -This is to make the language easier to parse for machines. Since the body of a |
154 |
| -macro can contain arbitrary tokens, some restriction is needed to allow simple |
155 |
| -non-macro-expanding lexers and parsers. This comes in the form of requiring |
156 |
| -that all delimiters be balanced. |
157 |
| - |
158 |
| -## `->` for function return type |
159 |
| - |
160 |
| -This is to make the language easier to parse for humans, especially in the face |
161 |
| -of higher-order functions. `fn foo<T>(f: fn(i32): i32, fn(T): U): U` is not |
162 |
| -particularly easy to read. |
163 |
| - |
164 |
| -## Why is `let` used to introduce variables? |
165 |
| - |
166 |
| -Instead of the term "variable", we use "variable bindings". The |
167 |
| -simplest way for creating a binding is by using the `let` syntax. |
168 |
| -Other ways include `if let`, `while let`, and `match`. Bindings also |
169 |
| -exist in function argument positions. |
170 |
| - |
171 |
| -Bindings always happen in pattern matching positions, and it's also Rust's way |
172 |
| -to declare mutability. One can also re-declare mutability of a binding in |
173 |
| -pattern matching. This is useful to avoid unnecessary `mut` annotations. An |
174 |
| -interesting historical note is that Rust comes, syntactically, most closely |
175 |
| -from ML, which also uses `let` to introduce bindings. |
176 |
| - |
177 |
| -See also [a long thread][alt] on renaming `let mut` to `var`. |
178 |
| - |
179 |
| -[alt]: https://mail.mozilla.org/pipermail/rust-dev/2014-January/008319.html |
180 |
| - |
181 |
| -## Why no `--x` or `x++`? |
182 |
| - |
183 |
| -Preincrement and postincrement, while convenient, are also fairly complex. They |
184 |
| -require knowledge of evaluation order, and often lead to subtle bugs and |
185 |
| -undefined behavior in C and C++. `x = x + 1` or `x += 1` is only slightly |
186 |
| -longer, but unambiguous. |
| 3 | +This content has moved to [the website](https://www.rust-lang.org/). |
0 commit comments