Make (Some) Separators Optional


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


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

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.

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.


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.


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.


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.


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

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

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

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?


This is patently false. Rust accepts semicolons after many of the constructs that you list, and sometimes it requires them! (not at the parsing stage, but rather; the lack of a semicolon causes it to be type-checked against ())

fn main() {
    if true { 3 } else { 4 }; // <-- this semicolon is REQUIRED, else type error!
    let _ = 2;

    loop {
        break 2;
    }; // <-- this semicolon is REQUIRED, else type error!
    let _ = 2;

I’m not saying that the above is useful; but I dare not call rust’s rules for semicolons intuitive or consistent!

Edit: Or then again, I did say it myself that ; is a statement. Maybe these are parsed as loop {...} (some sort of “expression statement”), ; (a statement), and let _ = 2; (a statement)?


-1 from me for allowing code like:

struct Zerg { ... }; 

In D language we have had to work a lot to disallow things like that.

Instead of messing with the language, it’s better to introduce auto-fixes in the editors/IDEs, in the rustfmt, etc.


Agreed completely. Let’s have one canonical syntax, please, rather than trying to hide errors.


I’m not sure if it has been mentioned but Lua had newlines as a token until recently. now it’s just whitespace and the devs like it better that way.

Ambiguous cases by removing semicolons:


This will likely just error. In Lua it errors at runtime (usually). Then you can just insert a semicolon where needed.

Just because it messes with your brain doesn’t mean it’s bad. Coffee also messes with your brain. :wink:


I truly hope this sentiment doesn’t take hold in Rust. This kind of ambiguous nonsense should be avoided at all cost.


at least it’s not context-sensitive.


Ouch. It’s exactly because it’s easy to use incorrectly that it is bad. Rust is not the average fast-and-loose scripting language. Rather, it is meant to emphasize safety and correctness as its number one goal. “It might break silently or at runtime because whitespace” doesn’t match with that goal by any standard.


Unfortunately, the forum only allows but one heart to give!


From my experience the best of both worlds is to infer semicola, but have editor display them.

Of course dropping mandatory semicola requires some adjustments to the rules on which tokens can continue an expression and those which cannot – but this is pretty much what every language not having mandatory semicola already does.

As is, Rust’s mandatory semicola are inconsistent, irritating and unnecessary.

Should Rust drop mandatory semicola? Yes.


They might be subjectively irritating for some people; however, they are neither inconsistent nor unnecessary. As several other people and I have explained above, they are necessary for unambiguous parsing. No question about that.


This is not true. The reason why Rust doesn’t use layout syntax is simple: there’s only so much in the complexity budget, and {, } and ; is used so that the language is more familiar to those who know a C-family language (C, C++, Java, and many more…).

It has nothing to do with some supposed objective drawback in readability of layout syntax. If you want to argue that and convince me, please provide some evidence.

That said; I don’t think introducing layout syntax or omitting ; in Rust is a good idea; the language is just not designed to be like Haskell, and so adding it after the fact won’t lead anywhere good.


neither inconsistent

struct Foo1;    // allowed
struct Foo2 {}  // alowed
struct Foo3 {}; // not allowed

impl Foo1;      // not allowed
impl Foo2 {}    // alowed
impl Foo3 {};   // not allowed

nor unnecessary

Please refer to my second sentence above.


is not valid syntax with or without a semicolon.

When we stick to things that are valid syntax in the first place, we get the aforementioned arguably consistent rule that an item ends in either a semicolon or a closing curly brace, but not both:

struct Foo1;    // allowed
struct Foo1     // not allowed
struct Foo2 {}  // alowed
struct Foo2 {}; // not allowed
struct Foo3();  // allowed
struct Foo3()   // not allowed

impl Foo1 {}    // alowed
impl Foo1 {};   // not allowed

(I have no particular opinion on whether this is the ideal rule for semicolon placement, but it does appear to be a consistent rule; I just want a lint against unnecessary semicolons)