
The infernal semicolon (2012) - tilt
https://brendaneich.com/2012/04/the-infernal-semicolon/
======
samatman
I never tire of comparing Lua with Javascript, and this is another one of
those cases. A semicolon in Lua is simply a character which is illegal to
place anywhere but the end of a statement.

There is no insertion stage, the language parses just fine on a single line,
or any whitespace you choose. Semicolons are vanishingly uncommon in Lua code,
but if you want to compress a couple statements onto a line, they signal your
intention.

Lua is like what Javascript would be if it were: based on Pascal, written by
resource-constrained Brazilians, and capable of making backwards-incompatible
changes. Though with the de-facto fork between Lua and LuaJIT, the latter has
become much more difficult, as it should at some point in the maturing of a
language.

~~~
tedunangst
I'm not sure Lua is that different than Javascript here. What is a semicolon
in Javascript if not a character you can only place at the end of a statement?
There are some similar ambiguities in the Lua parser if you insert a newline
into the middle of a statement.

The difference is that Lua is quite a bit fussier about statements versus
expressions, and won't allow things like "x() or y()" as statements. So the
Javascript example, translated to Lua, wouldn't compile with or without a
semicolon.

~~~
samatman
There are no such ambiguities. Here is the complete Lua grammar. You may
confirm for yourself that semicolons are always optional and that newlines
have no semantic meaning.

[http://www.lua.org/manual/5.1/manual.html#8](http://www.lua.org/manual/5.1/manual.html#8)

~~~
tedunangst

        x = fn (y)
    

Insert a newline:

    
    
        x = fn
        (y)
    

Syntax error. What happened? The newline has no semantic meaning.

~~~
samatman
Your problem is not what you think! Quite....

print(foo) ("x"):len()

This creates the same error. Deleting the newline gives you a new, different
error. A semicolon give the correct behavior. It's the edge case that the Lua
grammar can't resolve, and it does the sensible thing, by refusing to compile.

Also note that it is a compile-time _error_ that is described as an ambiguity.
It isn't a silent thing that bites you later, as in Javascript, and the
difference is huge.

[added] I'm not sure what you mean re "x() or y()" the following compiles
fine:

    
    
        function t()
        	return true
        end
        
        function f()
        	return false
        end
        
        if t() or f() then
        	print "logic"
        end
    

and does indeed print "logic".

~~~
tedunangst
Complete example:

    
    
        function fn(y)
            return y + 1
        end
        x = fn (1)
        print(x)
    

Works.

    
    
        function fn(y)
            return y + 1
        end
        x = fn
        (1)
        print(x)
    

Doesn't work. The only difference is a newline; clearly newlines do matter.
(And I specifically added the space to show that it's not simply whitespace
that matters.) This is, of course, documented in the manual.

For the original example, I meant that expressions are not valid statements.

    
    
        true or false
    

On a line by itself does not compile. It's an expression, but not a statement.

This is one of the things I like about Lua, that it prefers explicit over
clever, although sometimes the difference between statements and last
statements gets annoying. I'd like to do

    
    
        function fn()
            return nil
            -- more code, stubbed out for testing
        end
    

But you can't have code after return. Instead it needs to be wrapped with if
true.

~~~
samatman
Quite so. I didn't consider this aspect in my first post because it's a syntax
error, not an ambiguity; unlike Javascript, Lua won't resolve your ambiguity
for you.

I share your feeling about Lua being a bit more statement oriented than I'd
like. Have you checked out Moonscript?

------
ScottBurson
Somewhere, Alan Perlis is looking down on this and laughing his head off.

(For those who don't know the reference: [0], #3.)

[0] [http://www.cs.yale.edu/homes/perlis-
alan/quotes.html](http://www.cs.yale.edu/homes/perlis-alan/quotes.html)

------
tel
OCaml's approach to semicolons is nice—they are clearly nothing more than
sequence markers between side-effecting expressions.

    
    
        a ; b    (* a THEN       b *)
        a   b    (* a APPLIED TO b *)
    

You also can basically just desugar them to let bindings

    
    
        a ; b
        ==
        let _ = a in b
    
        a ; b ; c ; d e
        ==
        let _ = a in 
        let _ = b in
        let _ = c in
        d e
    

Due to static typing it's vanishingly unlikely that a forgotten semicolon will
properly check.

    
    
        let this = x ; y (* if x : 'a       and y : 'b then this : 'b *)
        let this = x   y (* if x : 'a -> 'b and y : 'a then this : 'b *)
    

So forgetting a semicolon only check if `x` is an unapplied function of type
`'a -> 'a` which the value you intended to completely ignore.

~~~
DonPellegrino
The desugar'd version should be

    
    
      let () = ...
    

instead of

    
    
      let _ = ...

~~~
tel
Huh. Certainly true stylistically, although OCaml accepts things like `1 + 1;
print_endline "hello";;` with just a warning.

------
marijn
The real surprise here is that people still use JSMin, written by an
opinionated grump who apparently does not understand the concept of using a
real parser. Several superior alternatives exist. UglifyJS is better in every
respect.

------
implicit
Is ASI really worth the amount of time that has been spent discussing it?

It would be nice if it were deleted from the language entirely.

~~~
pcwalton
Can't do that. Web sites rely on it.

~~~
implicit
Even as a pragma, a la "use strict"?

"use stricter"?

~~~
BrendanEich
No, because:

1\. Modes are bad for implementations (this feeling was strong from V8 folks
such as Erik Corry, but the new crew in Munich may not feel the same way), due
to code branching burdens in testing and optimizing while keeping the
complexity down.

2\. Worse, what you propose would fork the language to double the testing
burden for web devs (apart from engine implentors, item 1), since older
browsers would ignore the useless expression statement.

This already happened with ES5 "use strict", and created real world bugs
(e.g.,
[https://bugzilla.mozilla.org/show_bug.cgi?id=631043](https://bugzilla.mozilla.org/show_bug.cgi?id=631043),
there are more like this).

Developers do not test all the combinations. Notice how a tower of M modes
implemented via these string-expression-statement prologue directives can make
a 2^M-fold testing burden.

~~~
stupidcar
Aren't Google now proposing a bunch of new pragmas?

[http://www.2ality.com/2015/02/soundscript.html](http://www.2ality.com/2015/02/soundscript.html)

~~~
BrendanEich
As noted in item 1 ("new crew in Munich"), but these may both throw early
errors, not let code get to runtime with different semantics (as ES5 strict
did, due to arguments object and a few other changes), _and_ use real pragma
syntax, which will fail in old user agents.

How can real pragma syntax work on the Web? Only by using a compiler such as
Traceur or Babel, otherwise old browsers would choke on the `use types;`
unquoted directive.

Note how this can still complicate VMs, but it doesn't fork the test load for
web developers. And if the type system results in early errors, plus better
optimization with unforked runtime semantics, then the only burden on VM
implementors is in the parser and type checker.

We shall see how this experiment works, but in no way is it like `"use
stricter";`.

~~~
matt_kantor
> use real pragma syntax, which will fail in old user agents

> We shall see how this experiment works, but in no way is it like `"use
> stricter";`.

I might be misunderstanding your comment, but stupidcar's link
([http://www.2ality.com/2015/02/soundscript.html](http://www.2ality.com/2015/02/soundscript.html))
mentions `"use stricter;"` and `"use stricter+types;"` as mode flags, although
it also contains a big disclaimer ("The final version of SoundScript may look
and work completely different").

Has the syntax been changed since February? If so, I'm interested in reading
about it (but my Google-fu is failing); got a link?

~~~
BrendanEich
That talk on which Axel Rauschmayer reported had some info from a presentation
given by Andreas Rossberg of the V8 team to the last TC39 meeting. Here's the
PDF:

[http://www.mpi-
sws.org/~rossberg/papers/JSExperimentalDirect...](http://www.mpi-
sws.org/~rossberg/papers/JSExperimentalDirections.pdf)

There are two ideas:

1\. A `"use stricter";` (originally "use sanity" :-/) prologue directive that
would not change runtime semantics for code that passed all of static checks,
(control flow dependent) dynamic exception-throwing tests, and runtime
restrictions on object behavior.

2\. A "SoundScript" mode, perhaps enabled by a `use types;` opt-in, or
expressed some other way (per module?), that enables gradual type checking
based on optional annotations inspired by TypeScript, but with TS-incompatible
differences.

Mode 1 _might_ fly with TC39, because it does not fork semantics for code that
passes all checks. But for real-world code, there will be divergence when run
on old vs. new browsers, so I expect push-back in TC39 on this mode being
expressed by a useless string expression statement.

Mode 2 cannot be enabled by a fake-string-expression-statement "prologue
directive".

~~~
matt_kantor
Thanks! This looks promising. Gradual typing is something I've been wanting in
JavaScript ever since ES4 got my hopes up.

------
TheAceOfHearts
Every time someone brings up semicolons I think it's worth posting Isaac
Schlueter's blog post on the topic: [http://blog.izs.me/post/2353458699/an-
open-letter-to-javascr...](http://blog.izs.me/post/2353458699/an-open-letter-
to-javascript-leaders-regarding)

You can get by perfectly fine without semicolons. Going further, if you're
using a linter like eslint, I think you can even configure it to give you a
warning when the missing semicolon could cause problems.

~~~
lbotos
The biggest problem I have is the "leaders" forgetting the beginners. The
whole semicolon thing took JS from "end a statement with a ;" to:

THE RULES:

In general, \n ends a statement unless:

1\. The statement has an unclosed paren, array literal, or object literal or
ends in some other way that is not a valid way to end a statement. (For
instance, ending with . or ,.)

2\. The line is -- or ++ (in which case it will decrement/increment the next
token.)

3\. It is a for(), while(), do, if(), or else, and there is no {

4\. The next line starts with [, (, +, *, /, -, ,, ., or some other binary
operator that can only be found between two tokens in a single expression.

You have a junior dev now that's 2 steps behind because he's worrying about
self-imposed "beatifying" edge cases instead of getting his code to run.

------
rgrannell1
Not using semicolons has never be a problem for me.

Just like everyone else I put them where they are needed. I don't put them
where they aren't needed, because they aren't needed and adding pointless
syntax noise is dumb. If I forget to put them in somewhere they are needed, as
anyone might do, I add them. No problems.

~~~
IshKebab
The problem is that the rules for remembering where they are needed are hard
to remember and error-prone.

~~~
BrendanEich
See
[http://inimino.org/~inimino/blog/javascript_semicolons](http://inimino.org/~inimino/blog/javascript_semicolons),
hope it helps. The minimal semicolon style has only a few rules and many
people find it easier to use and remember. I've used it but my C hacker habits
go against it. It's a fine style.

/be

~~~
aikah
Wow neat,yeah, js devs are going to call anyone out that doesnt use
semicolons.

Question : If you ever wanted 1 breaking change in the language, and somehow
it would be possible (I know it wouldn't) what feature would you change ?
Again just 1 feature.

~~~
BrendanEich
I would undo the implicit conversion madness around == and !=.

~~~
cozuya
Is that really a big concern today where == is heavily frowned on by just
about everyone due to the above and its slowness?

~~~
BrendanEich
== is not slow when types of operands (in typeof sense) match -- then it's
equivalent to ===.

You'll find a lot of == out there, or would if only Google code search were
still up.

Hey, I got to answer with the one thing I'd change. There are more than a few,
and I had to pick. Losing the equivalence relation I had in the first ten days
(apart from NaN != NaN of course) was my pick.

------
panic
Previously:
[https://news.ycombinator.com/item?id=3844302](https://news.ycombinator.com/item?id=3844302)

------
cpeterso
Which programming language first used a semicolon as a statement delimiter?
Did they choose the semicolon because it was easy to type on a QWERTY
keyboard? Why not end a statement with a period like a sentence?

------
WorldWideWayne
A while back I think there was a github issue where the authors of some
popular library refused to use semi-colons and it was causing all sorts of
problems for people. I can't remember what library, but it was funny watching
hundreds of people comment on the issue to say "Just use the damn semi-
colons!"

~~~
tedunangst
The first link from the article in question?

~~~
WorldWideWayne
Haha, yeah I guess should have followed that link :)

------
serve_yay
I see these warnings a lot, but I work on a team that does not ever use
semicolons, and hasn't for years. It is simply not a problem, I don't know
what else to say. And I have come to really dislike the syntactic noise the
semicolons add.

~~~
BrendanEich
Do you start files with a leading ; just in case (of concatenation, where the
file otherwise would start with one of `([+-/`)?

Do you use ; at end of var declarations? If not, beware; if so, do you use
comma-first? Thanks for answers, just curious.

~~~
b_hell_t
I use var foo = 'bar'; but at my place of work they insist on no semi-colons
and comma first. I want to tell them this is stupid but I need solid facts.
anyone care to expand.

~~~
BrendanEich
If you happen to write

    
    
      var foo = 'bar',
          baz = 'bletch'
      (function (global) {
        //module pattern code here ...
      })(this);
    

then you have trouble. Semicolons are _not_ optional (meaning always optional,
you can leave them out at will). Please read my blog post.

~~~
jedschmidt
I wish `void` would get more love for IIFEs instead of just sitting there in a
dark corner of JS, unloved.

    
    
        var foo = 'bar'
        var baz = 'bletch'
        
        void function (global) {
          //module pattern code here ...
        })(this)

~~~
Havvy
Almost perfect, but you left an unmatched close parenthesis before the call
operator.

