# Make (Some) Separators Optional

**URL:** <https://internals.rust-lang.org/t/make-some-separators-optional/4846>\
**Category:** language design\
**Created:** [February 24, 2017, 6:59pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846 "2017-02-24T18:59:54Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [February 27, 2017, 4:04pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/22 "2017-02-27T16:04:13Z")

</div>

Single-function trait declaration requires ; after the function. This particular case looks odd to me because fn{} must not have a semicolon.

---

<div class="post-metadata">

**Author:** ![ahmedcharles](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ahmedcharles/32/4041_2.png) [@ahmedcharles](https://internals.rust-lang.org/u/ahmedcharles)\
**Post date:** [February 28, 2017, 5:12am UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/23 "2017-02-28T05:12:43Z")

</div>

Lua was mentioned and is interesting in that whitespace isn’t significant. The EBNF also fits on approximately one screen: [https://www.lua.org/manual/5.3/manual.html#9](https://www.lua.org/manual/5.3/manual.html#9)

The following code is (I think) the only ambiguity due to having optional semicolons:

```rust
local a = 0
local b = a
("%d"):format(b)

```

Here, `a("%d")` is parsed as a function call rather than as assigning a to b and then calling format on the string “%d”.

However, in this case, the result of the format function is being ignored, which makes it contrived. I can’t really think of a non-contrived ambiguity, though I’m sure they exist.

My opinion about Rust and optional semicolons is that I’d prefer the redundancy, thanks.

---

<div class="post-metadata">

**Author:** ![notriddle](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/notriddle/32/14082_2.png) [@notriddle](https://internals.rust-lang.org/u/notriddle)\
**Post date:** [February 28, 2017, 6:03pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/24 "2017-02-28T18:03:43Z")

</div>

You might want to read some previous threads about the semicolons:

> [@Current syntax](https://internals.rust-lang.org/t/current-syntax/459):
>
> I have just started learning Rust and I thought it would be interesting for you to get some feedback where I struggle with (in terms of syntax design, which is the reason why I’m posting this here) and what I think of Rust so far. Don’t hesitate to delete this thread if this matter should be discussed somewhere else. Here is a code example (taken from the tutorial) and some comments about it: impl\<T: PartialEq\> PartialEq for List\<T\> { fn eq(&self, ys: &List\<T\>) -\> bool { // Match o…

> [@I'm moving away, here's my two cents](https://internals.rust-lang.org/t/im-moving-away-heres-my-two-cents/3767):
>
> Rust is a great language but I think it has problems. Those problems come from the the time Rust was being developed by Mozilla and more problems were created after it became a community project. This post is a critique to Rust language to help you guys to improve it. I started using it because I thought it would be a replacement for C because it has no garbage collection and zero-cost abstractions. What made you quit? What made me fed up was that I was getting SIGTRAP when I was trying to mak…

---

<div class="post-metadata">

**Author:** ![mgeisler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mgeisler/32/2041_2.png) [@mgeisler](https://internals.rust-lang.org/u/mgeisler)\
**Post date:** [March 4, 2017, 5:59pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/25 "2017-03-04T17:59:33Z")

</div>

I've had to do a lot of Go programming lately and have been bothered by the semicolons in Rust 🙂

> [@Storyyeller](#):
>
> Go also does automatic semicolon insertion, but it's somewhat tempered by embedding a style guide into the language and encouraging everyone to use an autoformatter.

Yes, and it turns out that style isn't just a recommendation, but actually necessary in some cases -- precisely due to the automatic semicolon insertion. That is, a program like this is illegal:

```go
func main()
{
	fmt.Println("Hello, playground")
}

```

I happen to prefer the usual Go style, but this kind of gotcha can be confusing and annoying to people who are used to being able to format the code like they like. Removing semicolons is not free since it basically imposes some restrictions that weren't there before.

So if Rust were to make some semicolons optional, please take great care to handle code like above nicely.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [March 29, 2017, 10:15pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/26 "2017-03-29T22:15:47Z")

</div>

I keep forgetting `;` after a large `let x = { … }` block.

```rust
if foo {
   bar
} else {
   baz
} // no ;

```

```rust
let x = if foo {
   bar
} else {
   baz
}; // ';' required!

```

So I’d vote to make that one optional 🙂

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [June 16, 2018, 4:19pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/27 "2018-06-16T16:19:46Z")

</div>

> [@kornel](#):
>
> ```rust
> let x = if foo {
> bar
> } else {
> baz
> }; // ';' required!
> 
> ```
> 
> So I’d vote to make that one optional 🙂

But that is because it's actually a `let` (of course). This case, too, would suffer from potential ambiguity, depending on what follows:

```rust
let z = {
    let _x = if foo { bar } else { baz }
    *p
}

```

Contrived, perhaps, but syntactically ambiguous without semicolons (multiplication or result value).

I personally don't like the proposal for the opposite reason: it prevents me from breaking long expressions into lines without having to worry that this might arbitrarily create an unintended split.

Hence I would argue the opposite, if anything: allow additional, superfluous semicolons where they don't hurt, such as at the end of `struct`s:

```rust
struct Zorg; // currently required
struct Zerg { ... }; // currently forbidden, could be allowed

```

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [June 16, 2018, 4:45pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/28 "2018-06-16T16:45:10Z")

</div>

> [@lordan](#):
>
> Hence I would argue the opposite, if anything: allow additional, superfluous semicolons where they don’t hurt, such as at the end of `struct` s:
> 
> ```rust
> struct Zorg; // currently required
> struct Zerg { ... }; // currently forbidden, could be allowed
> 
> ```

Yes, absolutely this! I have been writing in rust for two years and still without fail make this mistake every time I turn a unit struct into a struct with fields. What's more is that this is allowed:

```rust
fn func() {
    fn inner_func() -> u32 {
        3
    };

    // the above is "allowed" because it actually means:
    // fn inner_func() -> u32 { 3 } // <-- an item...
    // ; // <-- ...followed by a statement
}

```

which frequently appears as the result of turning a closure into a function, but causes errors once the inner function is pulled out to item level.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 8:42pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/29 "2018-06-16T20:42:23Z")

</div>

@ExpHP I would love it as well; I’ve also been bitten by `struct Foo {};` many times.

However, there seem to be backwards-compat hazards: [https://play.rust-lang.org/?gist=0db4692763e19e7c54c955f6bcd411f6&version=stable&mode=debug](https://play.rust-lang.org/?gist=0db4692763e19e7c54c955f6bcd411f6&version=stable&mode=debug)

Perhaps this is fixable by keeping in mind that a `;` was matched as an item, and then the macro will see this as having matched the next infinite sequence of `;` in matchers?

EDIT: A more refined rule would be to count the number of consecutive `;`s matched as an item, and count exactly that many `;`s as matched in a macro matcher.

If we can think of a good way to keep macros working I’d love to work with you on an RFC.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [June 16, 2018, 8:57pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/30 "2018-06-16T20:57:23Z")

</div>

> [@Centril](#):
>
> However, there seem to be backwards-compat hazards: [https://play.rust-lang.org/?gist=0db4692763e19e7c54c955f6bcd411f6&version=stable&mode=debug](https://play.rust-lang.org/?gist=0db4692763e19e7c54c955f6bcd411f6&version=stable&mode=debug)

I'm not sure what this is showing.

To be clear, my thought is for the single token `;` to be a valid item. Is your example intended to show that having `$a:item` match the input `;` is a backcompat hazard?

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 9:00pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/31 "2018-06-16T21:00:05Z")

</div>

> [@ExpHP](#):
>
> To be clear, my thought is for the single token `;` to be a valid item.

Yeah, that's my idea also.

> [@ExpHP](#):
>
> Is your example intended to show that having `$a:item` match the input `;` is a backcompat hazard?

Yes. If you naively just make `;` match an `item`, then those currently working macros will break I think.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [June 16, 2018, 9:01pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/32 "2018-06-16T21:01:48Z")

</div>

@Centril but they seem to work fine for `:stmt` matchers in statement context, so I’m not sure how they would be problematic for `:item` matchers in item context.

```rust
fn main() {
    macro_rules! i1 { ($($x:stmt);*) => {} }

    i1! { struct Foo {}; struct Bar {} }
    
    macro_rules! i2 { ($x:stmt; $y:stmt) => { } }
    
    i2! { struct Foo {}; struct Bar {} }
    
    macro_rules! i3 { ($x:stmt;; $y:stmt) => { } }

    i3! { struct Foo {};; struct Bar {} }
}

```

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [June 16, 2018, 9:03pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/33 "2018-06-16T21:03:14Z")

</div>

Rust currently gives a clear error for a semicolon at the end of the struct; it won’t pass silently. That makes it trivial to catch and remove.

```rust
error: expected item, found `;`
 --> src/main.rs:3:2
  |
3 | };
  | ^ help: consider removing this semicolon

```

Along the same lines, we could and should detect empty statements inside a function, and lint against those. Clippy had a [feature request](https://github.com/rust-lang-nursery/rust-clippy/issues/266) to do exactly that, but punted it to rustfmt. Perhaps we should reconsider adding that?

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 9:12pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/34 "2018-06-16T21:12:02Z")

</div>

> [@ExpHP](#):
>
> @Centril but they seem to work fine for `:stmt` matchers in statement context, so I’m not sure how they would be problematic for `:item` matchers in item context.

My concern is that in `macro_rules! i1 { ($($x:item);*) => {} }` the token `;` would eaten as an `item` and then there is no `;` to match as the separator. That is: given `struct F {}; struct G {}` it is interpreted as `struct F {};` and `struct G {}`.

> [@josh](#):
>
> Rust currently gives a clear error for a semicolon at the end of the struct; it won’t pass silently. That makes it trivial to catch and remove.

While the current diagnostic is better than nothing, I think this simple mistake occurs frequently enough to be in the way of writing flow; so making `struct Foo {};` legal would make life easier. We can normalize this via rustfmt, removing any redundant `;`s.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [June 16, 2018, 9:17pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/35 "2018-06-16T21:17:58Z")

</div>

> [@Centril](#):
>
> My concern is that in `macro_rules! i1 { ($($x:item);*) => {} }` the token `;` would eaten as an `item` and then there is no `;` to match as the separator. That is: given `struct F {}; struct G {}` it is interpreted as `struct F {};` and `struct G {}` .

Huh? I would think it matches just fine:

- `$x:item` matches `struct F {}`, stopping before the `;` because `struct F {};` is not a valid item (or a prefix thereof)
- `$();*` matches the semicolon nonterminal, and thus repeats
- `$x:item` matches `struct G {}`
- `$();*` does not match a semicolon, and thus ends
- EOF; the expansion succeeds

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [June 16, 2018, 9:20pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/36 "2018-06-16T21:20:59Z")

</div>

> [@theduke](#):
>
> done away with the mostly redundant need for semicolons and commas

They are not redundant – they are _necessary_ for unambiguous parsing. The designers didn't put them in the language out of pure passion.

> [@theduke](#):
>
> The parser would optionally accept a newline instead of a semicolon in those places.

That's a call for all sorts of pain. Rust is intentionally not the """convenient""" whitespace language – those – basically – heuristics tend to introduce all sorts of hard to debug errors arising out of discrepancies between what's "obvious" to the human eye vs. what rules and exceptions and special cases the compiler handles.

> [@theduke](#):
>
> Swift is a good example here, because it is very close to Rust syntax/feature wise (traditional C family, but with generics, pattern matching, lambdas, …), and is perfectly fine without them.

I am a long time Swift user and I can tell you, life would be much simpler in Swift with semicolons. The language has all sorts of ugly assumptions about where expressions and statements end, and it's just extremely irritating.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 9:23pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/37 "2018-06-16T21:23:03Z")

</div>

But `;` is now a valid item, so you’d get the following instead?

1. `$x:item` matches `struct F {}` since it is a valid item
2. `$x:item` matches `;` since it is a valid item
3. `;` is expected as a non-terminal separator, but it has already been matched in 2. The matcher fails.

---

<div class="post-metadata">

**Author:** ![ExpHP](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/exphp/32/6208_2.png) [@ExpHP](https://internals.rust-lang.org/u/ExpHP)\
**Post date:** [June 16, 2018, 9:26pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/38 "2018-06-16T21:26:17Z")

</div>

> [@Centril](#):
>
> `$x:item` matches `;` since it is a valid item

That would require it to attempt to parse two items right after the other, but `$(<stuff>)<delim>*` must match `<delim>` before it attempts to match `<stuff>` again.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 9:27pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/39 "2018-06-16T21:27:34Z")

</div>

> [@ExpHP](#):
>
> That would require it to attempt to parse two items right after the other, but `$(<stuff>)<delim>*` must match `<delim>` before it attempts to match `<stuff>` again.

Oh I see; that makes sense. Thanks.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [June 16, 2018, 9:31pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/40 "2018-06-16T21:31:58Z")

</div>

> [@Centril](#):
>
> While the current diagnostic is better than nothing, I think this simple mistake occurs frequently enough to be in the way of writing flow; so making `struct Foo {};` legal would make life easier. We can normalize this via rustfmt, removing any redundant `;` s.

Right now, we have a very consistent rule: you need semicolons after any construct that doesn't take braces, and you need to omit the semicolon after any construct that takes braces. For instance, `if {}`, `for {}`, `loop {}`, `if {} else {}`, `struct {}`, `enum {}`, `union {}`, and `extern {}` all _don't_ take semicolons. And for a variety of reasons we _can't_ change most of those. Making some subset of them ignore unnecessary semicolons seems like a trap for users; better to document the pattern consistently.

I do think, however, we could make the error message much clearer. Right now, it just acts like any other parse error. We could recognize this specific case and very specifically say "don't put a `;` after a `struct`" (and similarly for `union` and `enum`), to make the message more straightforward to understand and act on.

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [June 16, 2018, 9:40pm UTC](https://internals.rust-lang.org/t/make-some-separators-optional/4846/41 "2018-06-16T21:40:04Z")

</div>

> [@josh](#):
>
> you need to omit the semicolon after any construct that takes braces

You can have `;` after `{}` in an expression context:

```rust
fn main() {
    struct Foo {};
    
    ;;;
    
    if true {} else {};
}

```

This is permitted since `;` is interpreted as the expression `()`.

> [@josh](#):
>
> Making some subset of them ignore unnecessary semicolons seems like a trap for users; better to document the pattern consistently.

Why a subset? If `;` is an item, then it is permitted after `impl`, `extern`, `struct`, `union`, `enum`, `fn`, `trait` consistently.

EDIT: @ExpHP want to join me in #rust-lang on IRC to work on an RFC perhaps?

[Previous page](https://internals.rust-lang.org/t/make-some-separators-optional/4846.md?page=1)

[Next page](https://internals.rust-lang.org/t/make-some-separators-optional/4846.md?page=3)
