|  | 
|  | 1 | +# Semicolon Items | 
|  | 2 | + | 
|  | 3 | +- Feature Name: `semicolon_items` | 
|  | 4 | +- Start Date: 2018-06-17 | 
|  | 5 | +- RFC PR: | 
|  | 6 | +- Rust Issue: | 
|  | 7 | + | 
|  | 8 | +# Summary | 
|  | 9 | +[summary]: #summary | 
|  | 10 | + | 
|  | 11 | +The semicolon (`;`) is now accepted as an item, permitting a user to write | 
|  | 12 | +`struct Foo {};`, among other things. The `item` fragment specifier in a | 
|  | 13 | +`macro_rules` matcher will match `;`. | 
|  | 14 | + | 
|  | 15 | +# Motivation | 
|  | 16 | +[motivation]: #motivation | 
|  | 17 | + | 
|  | 18 | +## Leftover semicolons when refactoring | 
|  | 19 | + | 
|  | 20 | +Various common refactorings often leave behind extraneous semicolons, such as: | 
|  | 21 | + | 
|  | 22 | +* Replacing a closure with a `fn` item: | 
|  | 23 | +   | 
|  | 24 | +  ```rust | 
|  | 25 | +  let add_two = |x| x + 2; | 
|  | 26 | +   | 
|  | 27 | +  // becomes: | 
|  | 28 | +  fn add_two(x: u32) -> u32 { | 
|  | 29 | +      x + 2 | 
|  | 30 | +  }; | 
|  | 31 | +  ``` | 
|  | 32 | +   | 
|  | 33 | +* Adding a field to what was formerly a unit struct: | 
|  | 34 | + | 
|  | 35 | +  ```rust | 
|  | 36 | +  struct UnitExpr; | 
|  | 37 | +   | 
|  | 38 | +  // becomes: | 
|  | 39 | +  struct UnitExpr { | 
|  | 40 | +      span: Span, | 
|  | 41 | +  }; | 
|  | 42 | +  ``` | 
|  | 43 | + | 
|  | 44 | +* Changing a tuple struct into a braced struct: | 
|  | 45 | + | 
|  | 46 | +  ```rust | 
|  | 47 | +  struct Foo(String, usize); | 
|  | 48 | + | 
|  | 49 | +  // becomes: | 
|  | 50 | +  struct Foo { | 
|  | 51 | +      bar: String, | 
|  | 52 | +      baz: usize, | 
|  | 53 | +  }; | 
|  | 54 | +  ``` | 
|  | 55 | +  | 
|  | 56 | +The error emitted by the compiler in these circumstances is never | 
|  | 57 | +indicative of a bug, but nonetheless disturbs the flow of writing | 
|  | 58 | +and causes the user to have to wait and recompile. | 
|  | 59 | +During that time, the user's train of thought can easily be lost. | 
|  | 60 | + | 
|  | 61 | +## Improving consistency with items in `fn` bodies | 
|  | 62 | + | 
|  | 63 | +[compiletest_rs]: https://github.com/laumann/compiletest-rs/blob/master/src/runtest.rs#L2585-L2660 | 
|  | 64 | + | 
|  | 65 | +Incidentally, these extraneous semicolons are currently permitted on items | 
|  | 66 | +defined inside of `fn` bodies, as a consequence of the fact that `;` in | 
|  | 67 | +isolation is a valid *statement* (though not an item). | 
|  | 68 | +The following, slightly modified example is from [compiletest_rs]. | 
|  | 69 | + | 
|  | 70 | +```rust | 
|  | 71 | +fn read2_abbreviated(mut child: Child) -> io::Result<Output> { | 
|  | 72 | +    use std::mem::replace; | 
|  | 73 | +    use read2::read2; | 
|  | 74 | + | 
|  | 75 | +    const HEAD_LEN: usize = 160 * 1024; | 
|  | 76 | +    const TAIL_LEN: usize = 256 * 1024; | 
|  | 77 | + | 
|  | 78 | +    enum ProcOutput { | 
|  | 79 | +        Full(Vec<u8>), | 
|  | 80 | +        Abbreviated { | 
|  | 81 | +            head: Vec<u8>, | 
|  | 82 | +            skipped: usize, | 
|  | 83 | +            tail: Box<[u8]>, | 
|  | 84 | +        } | 
|  | 85 | +    }; | 
|  | 86 | + | 
|  | 87 | +    impl ProcOutput { | 
|  | 88 | +        ... | 
|  | 89 | +    }; | 
|  | 90 | + | 
|  | 91 | +    ... | 
|  | 92 | +} | 
|  | 93 | +``` | 
|  | 94 | + | 
|  | 95 | +By permitting semicolons as items outside of `fn` bodies, | 
|  | 96 | +a modicum of consistency in the Rust's grammar can be gained. | 
|  | 97 | + | 
|  | 98 | +## A frequent editing mistake | 
|  | 99 | + | 
|  | 100 | +For the authors of this RFC, who have written Rust code for many years, | 
|  | 101 | +it still sometimes happens that they mistakenly place a semicolon after | 
|  | 102 | +`struct Name {}`. As previously mentioned, such trivialities needlessly | 
|  | 103 | +disrupt the editing process. | 
|  | 104 | + | 
|  | 105 | +## Retaining a uniform style | 
|  | 106 | + | 
|  | 107 | +To retain as uniform of a style possible in the Rust community, | 
|  | 108 | +this RFC proposes that `rustfmt`, Rust's code formatting tool, | 
|  | 109 | +should remove extraneous `;` since they are most likely left over | 
|  | 110 | +while editing or as a frequently made mistake. | 
|  | 111 | +No possibility of configuring this behavior of `rustfmt` is proposed at this time. | 
|  | 112 | + | 
|  | 113 | +# Guide-level explanation | 
|  | 114 | +[guide-level-explanation]: #guide-level-explanation | 
|  | 115 | + | 
|  | 116 | +Simply put, the token `;` is now accepted as an item. | 
|  | 117 | +This means that you are allowed to write all of the following: | 
|  | 118 | + | 
|  | 119 | +```rust | 
|  | 120 | +struct Foo { | 
|  | 121 | +    bar: Baz | 
|  | 122 | +}; // <-- NOTE | 
|  | 123 | +``` | 
|  | 124 | + | 
|  | 125 | +You can also put a `;` after `enum`, `trait`, `impl`, `fn`, `union`, | 
|  | 126 | +and `extern` items. | 
|  | 127 | + | 
|  | 128 | +A `macro_rules` matcher using the `item` fragment will now also accept | 
|  | 129 | +`;` as an item. For example, given: | 
|  | 130 | + | 
|  | 131 | +```rust | 
|  | 132 | +macro_rules foo! { | 
|  | 133 | +    ($x: item) => { .. } | 
|  | 134 | +} | 
|  | 135 | +``` | 
|  | 136 | + | 
|  | 137 | +you may write: | 
|  | 138 | + | 
|  | 139 | +```rust | 
|  | 140 | +foo!(;) | 
|  | 141 | +``` | 
|  | 142 | + | 
|  | 143 | +It's important to note that while `;` is now accepted where `item`s are, | 
|  | 144 | +this is not intended as the recommended style, but only to improve the | 
|  | 145 | +consistency in Rust's grammar, as well as writing flow. | 
|  | 146 | + | 
|  | 147 | +# Reference-level explanation | 
|  | 148 | +[reference-level-explanation]: #reference-level-explanation | 
|  | 149 | + | 
|  | 150 | +1. The token `;` is accepted as a valid item, both in the language syntax | 
|  | 151 | +and by the `item` macro 'fragment specifier'. As an example, `struct Foo {};` | 
|  | 152 | +is therefore in the language accepted by a Rust compiler. | 
|  | 153 | + | 
|  | 154 | +2. `rustfmt` will remove any extraneous `;` items. | 
|  | 155 | + | 
|  | 156 | +# Drawbacks | 
|  | 157 | +[drawbacks]: #drawbacks | 
|  | 158 | + | 
|  | 159 | +The language accepted by a Rust parser is made somewhat more complicated; | 
|  | 160 | +this can have some minor effect on parsing performance and will also | 
|  | 161 | +complicate the language users will need to understand. | 
|  | 162 | +However, we believe that nothing new is actually necessary to be learned | 
|  | 163 | +as a redundant `;` in an example such as `struct Foo {};` should already | 
|  | 164 | +be intuitive for someone who knows `struct Foo {}`. | 
|  | 165 | + | 
|  | 166 | +# Rationale and alternatives | 
|  | 167 | +[alternatives]: #rationale-and-alternatives | 
|  | 168 | + | 
|  | 169 | +## Do nothing | 
|  | 170 | + | 
|  | 171 | +As always, if we conclude that the motivation is not enough, | 
|  | 172 | +we can elect to do nothing. | 
|  | 173 | + | 
|  | 174 | +## Improve error messages further | 
|  | 175 | + | 
|  | 176 | +An idea due to [@joshtripplet](https://github.com/joshtriplett) is to improve | 
|  | 177 | +the error messages given by `rustc` instead of accepting redundant `;`s. | 
|  | 178 | + | 
|  | 179 | +The current error message when writing `struct Foo {};` is: | 
|  | 180 | + | 
|  | 181 | +```rust | 
|  | 182 | +error: expected item, found `;` | 
|  | 183 | + --> src/main.rs:1:14 | 
|  | 184 | +  | | 
|  | 185 | +1 | struct Foo {}; | 
|  | 186 | +  |              ^ help: consider removing this semicolon | 
|  | 187 | +``` | 
|  | 188 | + | 
|  | 189 | +This error message is already quite good, giving the user actionable | 
|  | 190 | +information. However, the specific case could be improved by recognizing it | 
|  | 191 | +specially and saying something like *"don't put a `;` after a `struct { ... }`"* | 
|  | 192 | +(same for `union`s and `enum`s). This idea is being discussed in [issue #51603](https://github.com/rust-lang/rust/issues/51603). | 
|  | 193 | + | 
|  | 194 | +However, this does not solve the problem when refactoring, | 
|  | 195 | +and neither does it enhance writing flow nor make the grammar more consistent. | 
|  | 196 | + | 
|  | 197 | +# Prior art | 
|  | 198 | +[prior-art]: #prior-art | 
|  | 199 | + | 
|  | 200 | +Rust is unusual in that it is a semicolon-terminated language, | 
|  | 201 | +yet it has very few kinds of statements that are not expressions in disguise. | 
|  | 202 | +This makes direct comparisons to other languages difficult.   | 
|  | 203 | + | 
|  | 204 | +There is however some prior art: | 
|  | 205 | + | 
|  | 206 | +* C++11 [added support](http://en.cppreference.com/w/cpp/language/declarations) | 
|  | 207 | +for `;` as an "empty declaration," where prior specifications of the language did not. | 
|  | 208 | + | 
|  | 209 | +* GHC, the Glasgow Haskell Compiler, accepts `;` at the top level. | 
|  | 210 | +For example, the following is accepted by GHC: | 
|  | 211 | + | 
|  | 212 | +  ```haskell | 
|  | 213 | +  module Foo where | 
|  | 214 | +  ; | 
|  | 215 | +  ``` | 
|  | 216 | + | 
|  | 217 | +# Unresolved questions | 
|  | 218 | +[unresolved]: #unresolved-questions | 
|  | 219 | + | 
|  | 220 | +* Does this create parsing ambiguities anywhere? | 
0 commit comments