|
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