When we started working on Go, we were more concerned with semantics
than syntax, but before long we needed to define the syntax in order
to write programs. One syntactic idea we tried was to reduce the
number of semicolons in the grammar, to make the source code cleaner- looking. We managed to get rid of many of them, but the grammar became
clumsy and hard to maintain as we worked on the compiler, and we
realized we had overreached. We backed up to a compromise that had
optional semicolons in a few places, a couple of rules about where
they go, and a tool (gofmt) to regularize them.
Although we acclimated to the rules and were comfortable with them,
once we launched it became clear that they were not really
satisfactory. The compromise didn't seem to fit right with most
programmers. The issue needed to be rethought.
The language BCPL, an ancestor to B, which is an ancestor to C, had an
interesting approach to semicolons. It can be summarized in two steps.
First, the formal grammar requires semicolons in statement lists.
Second, a lexical (not syntactic) rule inserts semicolons
automatically before a newline when required by the formal grammar.
In retrospect, had we thought of BCPL's approach at the time, we would
almost certainly have followed its lead.
We propose to follow it now.
Appended to this mail is a formal specification of the proposed rules
for semicolons in Go. They can be summarized much as in BCPL, but Go
is a different language so the detailed rules differ; see the
specification for the details. In short:
- In the formal grammar, semicolons are terminators, as in C.
- A semicolon is automatically inserted by the lexer if a line's
last token is an identifier, a basic literal, or one of the following
tokens: break continue fallthrough return ++ -- ) }
- A semicolon may be omitted before a closing ) or } .
The upshot is this: given the proposal, most required semicolons are
inserted automatically and thus disappear from Go programs, except in
a few situations such as for loop clauses, where they will continue to
separate the elements of the clause.
No more optional semicolons, no more rewriting; they're just gone. You
can put them in if you want, but we believe you'll quickly stop and
gofmt will throw them away.
The code will look much cleaner.
There are compatibility issues. A few things break with this proposal,
but not many. (When processing the .go files under src/pkg with an
updated parser, most files are accepted under the old and new rules.)
By far the most important breakage is lexical string concatenation
across newlines, as in
"hello "
"world"
Since the language permits + to concatenate strings and constant
folding is done by the compilers, this feature is simply gone from the
language; use a + to concatenate strings. It's not a huge loss because
`` strings can still span newlines.
With the new rules, a semicolon is mistakenly inserted after the last
element of a multi-line list if the closing parenthesis or brace is on
a separate line:
f(
a,
b
)
To avoid this issue, a trailing comma is now permitted in function
calls and formal parameter lists, as is the case with composite
literals already.
A channel send spanning a newline can accidentally become a receive,
as in
a = b
<-c
Inserting a semicolon after the b changes the meaning from a non- blocking send to an assignment followed by a receive. For this
transformation to mislead, however, the types of a, b and c must be
very specific: interface{}, chan interface{} and chan. So a program
might break but it is almost certain never to succeed incorrectly. We
are aware of the risk but believe it is unimportant.
A similar thing can happen with certain function calls:
f()
(g())
If f() returns a function whose single argument matches the type of a
parenthesized expression such as (g()), this will also erroneously
change meaning. Again, this is so rare we believe it is unimportant.
Finally, a return statement spanning a newline is broken up into two
statements:
return
f()
For this to miscompile, the return statement must be in a function
with a single named result, and the result expression must be
parseable as a statement.
Gofmt's style already avoids all three problematic formattings.
This proposal may remind you of JavaScript's optional semicolon rule,
which in effect adds semicolons to fix parse errors. The Go proposal
is profoundly different. First, it is a lexical model, not a semantic
one, and we believe that makes it far safer in practice. The rules are
hard and fast, not subject to contextual interpretation. Second, since
very few expressions in Go can be promoted to statements, the
opportunities where confusion can arise are also very few - they're
basically the examples above. Finally, since Go is statically type- safe, the odds are even lower.
Another language the proposal may evoke is Python, which uses white
space for indentation. Again, the story here is very different.
Program structure is not defined by white space. Instead, a much
milder thing is happening: lists of statements, constants, etc. may be
separated by placing them one per line instead of by inserting
semicolons. That's all.
Please read the proposal and think about its consequences. We're
pretty sure it makes the language nicer to use and sacrifices almost
nothing in precision or safety.
Rolling out the change.
Gofmt will be a big help in pushing out this change. Here is the plan.
1. Change gofmt to insert the + for string concatenation. Give it a
flag to omit the semicolons but leave them in by default.
2. Reformat the tree with that gofmt: this inserts + for lexical
string concatenation but otherwise is a no-op.
3. Update the compilers to insert semicolons. They should then accept
gofmt output (with semicolons) and semicolon-free programs just fine.
4. Try things out, revising the specification and tools as required.
5. Once happy, make the gofmt default "no semicolons". Reformat the
entire tree.
The formal specification.
The following changes are applied to the spec.
1) New semicolon rules:
a) When the input is broken into tokens, a semicolon is automatically
inserted into the token stream at the end of a non-blank line if the
line's final token is:
- an identifier or basic literal
- one of the keywords break, continue, fallthrough or return
- one of the tokens ++ -- ) ] }
b) To allow complex statements to occupy a single line, a semicolon
may be omitted before a closing ) or }.
2) The interpretation of comments is clarified:
a) Line comments start with the character sequence // and continue
through the next newline. A line comment acts like a newline.
b) General comments start with the character sequence /* and continue
through the character sequence */. A general comment that spans
multiple lines acts like a newline, otherwise it acts like a space.
3) Replacements:
a) All uses of StringLit are replaced by string_lit.
b) All uses of StatementList are replaced by { Statement ";" }.
4) The following productions are simplified and always use semicolons
as terminators. In idiomatic use, the semicolons are inserted
automatically and thus won't appear in the source code.
5) The following productions permit optional commas. This enables
multi-line constructions where the closing parenthesis or brace is on
a new line if the last element is followed by a comma. The optional
comma is only new for parameter lists and calls; composite literals
permit it already.
7) The two exceptions about when semicolons may be omitted in
statement lists are superseded by 1b above.
Prime sieve example without trailing semicolons
package main
import "fmt"
// Send the sequence 2, 3, 4, ... to channel 'ch'.
func generate(ch chan<- int) {
for i := 2; ; i++ {
ch <- i // Send 'i' to channel 'ch'.
}
}
// Copy the values from channel 'src' to channel 'dst',
// removing those divisible by 'prime'.
func filter(src <-chan int, dst chan<- int, prime int) {
for i := range src { // Loop over values received from 'src'.
if i%prime != 0 {
dst <- i // Send 'i' to channel 'dst'.
}
}
}
// The prime sieve: Daisy-chain filter processes together.
func sieve() {
ch := make(chan int) // Create a new channel.
go generate(ch) // Start generate() as a subprocess.
for {
prime := <-ch
...
> No more optional semicolons, no more rewriting; they're just gone. You can
> put them in if you want, but we believe you'll quickly stop and gofmt will
> throw them away.
Wow, quite a move! Nice to see you guys still aren't afraid of big changes.
Seems like a really good compromise.
-- :: atomly ::
[ ato...@atomly.com : www.atomly.com : http://blog.atomly.com/ ...
[ atomiq records : new york city : +1.917.442.9450 ...
[ e-mail atomly-news-subscr...@atomly.com for atomly info and updates ...
On Wed, Dec 9, 2009 at 3:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
[...]
> Appended to this mail is a formal specification of the proposed rules for
> semicolons in Go. They can be summarized much as in BCPL, but Go is a
> different language so the detailed rules differ; see the specification for
> the details. In short:
> - In the formal grammar, semicolons are terminators, as in C.
> - A semicolon is automatically inserted by the lexer if a line's last
> token is an identifier, a basic literal, or one of the following tokens:
> break continue fallthrough return ++ -- ) }
> - A semicolon may be omitted before a closing ) or } .
> The upshot is this: given the proposal, most required semicolons are
> inserted automatically and thus disappear from Go programs, except in a few
> situations such as for loop clauses, where they will continue to separate
> the elements of the clause.
Please, don't. I know that making semicolons optional is popular and
is done in a number of popular languages like JavaScript and Ruby,
however I don't like it.
Which do you prefer to read? Which makes the structure of the
calculation clearer at a glance?
Your semi-colon insertion rule would make the first style break
horribly, and would force the second style. Which I think it
significantly worse.
That said, I do like allowing trailing commas in argument lists.
That's good because it makes errors less likely when you come along
and add another element to a list. But I like putting my operators
where my eye can scan down and see them.
> On Wed, Dec 9, 2009 at 3:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
> [...]
>> Appended to this mail is a formal specification of the proposed rules for
>> semicolons in Go. They can be summarized much as in BCPL, but Go is a
>> different language so the detailed rules differ; see the specification for
>> the details. In short:
>> - In the formal grammar, semicolons are terminators, as in C.
>> - A semicolon is automatically inserted by the lexer if a line's last
>> token is an identifier, a basic literal, or one of the following tokens:
>> break continue fallthrough return ++ -- ) }
>> - A semicolon may be omitted before a closing ) or } .
>> The upshot is this: given the proposal, most required semicolons are
>> inserted automatically and thus disappear from Go programs, except in a few
>> situations such as for loop clauses, where they will continue to separate
>> the elements of the clause.
> Please, don't. I know that making semicolons optional is popular and
> is done in a number of popular languages like JavaScript and Ruby,
> however I don't like it.
> Which do you prefer to read? Which makes the structure of the
> calculation clearer at a glance?
> Your semi-colon insertion rule would make the first style break
> horribly, and would force the second style. Which I think it
> significantly worse.
It's funny. I typed a response to this defending the change saying that it does what you want. But it doesn't; I misread your mail because I assumed you disliked the first form. Because I do; the second is the one preferred by everyone here. Those trailing operators make it clear that we're not done yet, which makes the code more readable to my eyes.
So to answer your questions: Which do I prefer to read? Which is clearer? The second.
I think these are minor points anyway. Again, it's about having a style, not what the style is. If the consequences of the rules were the other way around, I'd still be happy about them because I'd adjust quickly and not care. Gofmt saves all. Legislated taste trumps endless formatting arguments.
> That said, I do like allowing trailing commas in argument lists.
> That's good because it makes errors less likely when you come along
> and add another element to a list. But I like putting my operators
> where my eye can scan down and see them.
Yes. Please remove the semi colons entierly. I've been coding in
Python for too long to not be caught by them all too often.
As I like to point out in these discussions people frequently forget
to put the semi colons in at the end of a statement but it is very
rare that I forget to hit return at the end of a statement.
On Dec 10, 12:33 pm, "Rob 'Commander' Pike" <r...@google.com> wrote:
> > On Wed, Dec 9, 2009 at 3:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
> > [...]
> >> Appended to this mail is a formal specification of the proposed rules for
> >> semicolons in Go. They can be summarized much as in BCPL, but Go is a
> >> different language so the detailed rules differ; see the specification for
> >> the details. In short:
> >> - In the formal grammar, semicolons are terminators, as in C.
> >> - A semicolon is automatically inserted by the lexer if a line's last
> >> token is an identifier, a basic literal, or one of the following tokens:
> >> break continue fallthrough return ++ -- ) }
> >> - A semicolon may be omitted before a closing ) or } .
> >> The upshot is this: given the proposal, most required semicolons are
> >> inserted automatically and thus disappear from Go programs, except in a few
> >> situations such as for loop clauses, where they will continue to separate
> >> the elements of the clause.
> > Please, don't. I know that making semicolons optional is popular and
> > is done in a number of popular languages like JavaScript and Ruby,
> > however I don't like it.
> > Which do you prefer to read? Which makes the structure of the
> > calculation clearer at a glance?
> > Your semi-colon insertion rule would make the first style break
> > horribly, and would force the second style. Which I think it
> > significantly worse.
> It's funny. I typed a response to this defending the change saying that it does what you want. But it doesn't; I misread your mail because I assumed you disliked the first form. Because I do; the second is the one preferred by everyone here. Those trailing operators make it clear that we're not done yet, which makes the code more readable to my eyes.
> So to answer your questions: Which do I prefer to read? Which is clearer? The second.
> I think these are minor points anyway. Again, it's about having a style, not what the style is. If the consequences of the rules were the other way around, I'd still be happy about them because I'd adjust quickly and not care. Gofmt saves all. Legislated taste trumps endless formatting arguments.
> > That said, I do like allowing trailing commas in argument lists.
> > That's good because it makes errors less likely when you come along
> > and add another element to a list. But I like putting my operators
> > where my eye can scan down and see them.
On Wed, Dec 9, 2009 at 6:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
> - In the formal grammar, semicolons are terminators, as in C.
> - A semicolon is automatically inserted by the lexer if a line's last
> token is an identifier, a basic literal, or one of the following tokens:
> break continue fallthrough return ++ -- ) }
> - A semicolon may be omitted before a closing ) or } .
I think you're making things worse, this is more complicated than
before and for what? The *unbelievable* feature of being able to leave
out semicolons? I thought this was an April's fools message at first.
Sigh.
Who *cares* about leaving out semicolons? Hordes of C programmers
you're trying to convert? Unlikely, they are used to it! Hordes of
Python addicts? Unlikely since they'll complain about {} right away!
Do *you* really care? I mean is it really making your code a whole lot
better or more enjoyable to write? There are plenty of things to fix
in Go, and you fix *semicolons*?
Don't get me wrong, I really, really like Go. Heck, I do almost
nothing but write Go code these days, for hours, and for fun. But I
strongly believe that you're heading the wrong way by adding more
rules to achieve a goal that's dubious in the first place.
Heck, you could probably have Robert Griesemer put together a clean
Oberon-style syntax in a few hours that would make all this go away.
Or just go for *real* C-style if you still believe that the world
can't deal with capitalized keywords. Either is a lot simpler than a
whole bunch of special cases. Yeah, I don't have to remember them
because of gofmt. Programming languages shouldn't depend on tools,
they should make good sense by themselves.
Just my $0.02 of course. Sorry for the rant, I don't mean to flame
anyone. I mean to flame the topic.
Cheers,
Peter
-- Peter H. Froehlich <http://www.cs.jhu.edu/~phf/>
Senior Lecturer | Director, Johns Hopkins Gaming Lab
I would like to clarify when a semicolon might be required. Presumably
when there are multiple statements on a line. I've constructed a
plausible test case for you.
// Semicolons in Go : Test case
// multiple statements on a line
// import ("fmt"; "os";)
// c[j] = b[i]; j++;
package main
import ("fmt"; "os";)
func nospaces(b []byte) (c []byte, err os.Error)
{
c = make([]byte, len(b));
for i, j := 0, 0; i < len(b) && j < len(c); i++ {
if b[i] != ' ' {
c[j] = b[i]; j++;
}
}
return;
> When we started working on Go, we were more concerned with semantics
> than syntax, but before long we needed to define the syntax in order
> to write programs. One syntactic idea we tried was to reduce the
> number of semicolons in the grammar, to make the source code cleaner-
> looking. We managed to get rid of many of them, but the grammar became
> clumsy and hard to maintain as we worked on the compiler, and we
> realized we had overreached. We backed up to a compromise that had
> optional semicolons in a few places, a couple of rules about where
> they go, and a tool (gofmt) to regularize them.
> Although we acclimated to the rules and were comfortable with them,
> once we launched it became clear that they were not really
> satisfactory. The compromise didn't seem to fit right with most
> programmers. The issue needed to be rethought.
> The language BCPL, an ancestor to B, which is an ancestor to C, had an
> interesting approach to semicolons. It can be summarized in two steps.
> First, the formal grammar requires semicolons in statement lists.
> Second, a lexical (not syntactic) rule inserts semicolons
> automatically before a newline when required by the formal grammar.
> In retrospect, had we thought of BCPL's approach at the time, we would
> almost certainly have followed its lead.
> We propose to follow it now.
> Appended to this mail is a formal specification of the proposed rules
> for semicolons in Go. They can be summarized much as in BCPL, but Go
> is a different language so the detailed rules differ; see the
> specification for the details. In short:
> - In the formal grammar, semicolons are terminators, as in C.
> - A semicolon is automatically inserted by the lexer if a line's
> last token is an identifier, a basic literal, or one of the following
> tokens: break continue fallthrough return ++ -- ) }
> - A semicolon may be omitted before a closing ) or } .
> The upshot is this: given the proposal, most required semicolons are
> inserted automatically and thus disappear from Go programs, except in
> a few situations such as for loop clauses, where they will continue to
> separate the elements of the clause.
> No more optional semicolons, no more rewriting; they're just gone. You
> can put them in if you want, but we believe you'll quickly stop and
> gofmt will throw them away.
> The code will look much cleaner.
> There are compatibility issues. A few things break with this proposal,
> but not many. (When processing the .go files under src/pkg with an
> updated parser, most files are accepted under the old and new rules.)
> By far the most important breakage is lexical string concatenation
> across newlines, as in
> "hello "
> "world"
> Since the language permits + to concatenate strings and constant
> folding is done by the compilers, this feature is simply gone from the
> language; use a + to concatenate strings. It's not a huge loss because
> `` strings can still span newlines.
> With the new rules, a semicolon is mistakenly inserted after the last
> element of a multi-line list if the closing parenthesis or brace is on
> a separate line:
> f(
> a,
> b
> )
> To avoid this issue, a trailing comma is now permitted in function
> calls and formal parameter lists, as is the case with composite
> literals already.
> A channel send spanning a newline can accidentally become a receive,
> as in
> a = b
> <-c
> Inserting a semicolon after the b changes the meaning from a non-
> blocking send to an assignment followed by a receive. For this
> transformation to mislead, however, the types of a, b and c must be
> very specific: interface{}, chan interface{} and chan. So a program
> might break but it is almost certain never to succeed incorrectly. We
> are aware of the risk but believe it is unimportant.
> A similar thing can happen with certain function calls:
> f()
> (g())
> If f() returns a function whose single argument matches the type of a
> parenthesized expression such as (g()), this will also erroneously
> change meaning. Again, this is so rare we believe it is unimportant.
> Finally, a return statement spanning a newline is broken up into two
> statements:
> return
> f()
> For this to miscompile, the return statement must be in a function
> with a single named result, and the result expression must be
> parseable as a statement.
> Gofmt's style already avoids all three problematic formattings.
> This proposal may remind you of JavaScript's optional semicolon rule,
> which in effect adds semicolons to fix parse errors. The Go proposal
> is profoundly different. First, it is a lexical model, not a semantic
> one, and we believe that makes it far safer in practice. The rules are
> hard and fast, not subject to contextual interpretation. Second, since
> very few expressions in Go can be promoted to statements, the
> opportunities where confusion can arise are also very few - they're
> basically the examples above. Finally, since Go is statically type-
> safe, the odds are even lower.
> Another language the proposal may evoke is Python, which uses white
> space for indentation. Again, the story here is very different.
> Program structure is not defined by white space. Instead, a much
> milder thing is happening: lists of statements, constants, etc. may be
> separated by placing them one per line instead of by inserting
> semicolons. That's all.
> Please read the proposal and think about its consequences. We're
> pretty sure it makes the language nicer to use and sacrifices almost
> nothing in precision or safety.
> Rolling out the change.
> Gofmt will be a big help in pushing out this change. Here is the plan.
> 1. Change gofmt to insert the + for string concatenation. Give it a
> flag to omit the semicolons but leave them in by default.
> 2. Reformat the tree with that gofmt: this inserts + for lexical
> string concatenation but otherwise is a no-op.
> 3. Update the compilers to insert semicolons. They should then accept
> gofmt output (with semicolons) and semicolon-free programs just fine.
> 4. Try things out, revising the specification and tools as required.
> 5. Once happy, make the gofmt default "no semicolons". Reformat the
> entire tree.
> The formal specification.
> The following changes are applied to the spec.
> 1) New semicolon rules:
> a) When the input is broken into tokens, a semicolon is automatically
> inserted into the token stream at the end of a non-blank line if the
> line's final token is:
> - an identifier or basic literal
> - one of the keywords break, continue, fallthrough or return
> - one of the tokens ++ -- ) ] }
> b) To allow complex statements to occupy a single line, a semicolon
> may be omitted before a closing ) or }.
> 2) The interpretation of comments is clarified:
> a) Line comments start with the character sequence // and continue
> through the next newline. A line comment acts like a newline.
> b) General comments start with the character sequence /* and continue
> through the character sequence */. A general comment that spans
> multiple lines acts like a newline, otherwise it acts like a space.
> 3) Replacements:
> a) All uses of StringLit are replaced by string_lit.
> b) All uses of StatementList are replaced by { Statement ";" }.
> 4) The following productions are simplified and always use semicolons
> as terminators. In idiomatic use, the semicolons are inserted
> automatically and thus won't appear in the source code.
> 5) The following productions permit optional commas. This enables
> multi-line constructions where the closing parenthesis or brace is on
> a new line if the last element is followed by a comma. The optional
> comma is only new for parameter lists and calls; composite literals
> permit it already.
> I would like to clarify when a semicolon might be required. Presumably
> when there are multiple statements on a line. I've constructed a
> plausible test case for you.
Yes, semicolons can be used to separate multiple
statements on a single line. But the standard
formatting will be to separate them with newlines instead.
Python programmer here, not complaining about braces. If you remove
braces you need to add significant whitespace, which has its own
problems. I may like it in python but I'm not advocating it.
Really it is much better for Go to move from its semicolons are
optional sometimes to one of the extremes of semicolons are optional
or semicolons are required. I say go for optional.
regs
Kornad
On Dec 10, 1:08 pm, Peter Froehlich <peter.hans.froehl...@gmail.com>
wrote:
> On Wed, Dec 9, 2009 at 6:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
> > - In the formal grammar, semicolons are terminators, as in C.
> > - A semicolon is automatically inserted by the lexer if a line's last
> > token is an identifier, a basic literal, or one of the following tokens:
> > break continue fallthrough return ++ -- ) }
> > - A semicolon may be omitted before a closing ) or } .
> I think you're making things worse, this is more complicated than
> before and for what? The *unbelievable* feature of being able to leave
> out semicolons? I thought this was an April's fools message at first.
> Sigh.
> Who *cares* about leaving out semicolons? Hordes of C programmers
> you're trying to convert? Unlikely, they are used to it! Hordes of
> Python addicts? Unlikely since they'll complain about {} right away!
> Do *you* really care? I mean is it really making your code a whole lot
> better or more enjoyable to write? There are plenty of things to fix
> in Go, and you fix *semicolons*?
> Don't get me wrong, I really, really like Go. Heck, I do almost
> nothing but write Go code these days, for hours, and for fun. But I
> strongly believe that you're heading the wrong way by adding more
> rules to achieve a goal that's dubious in the first place.
> Heck, you could probably have Robert Griesemer put together a clean
> Oberon-style syntax in a few hours that would make all this go away.
> Or just go for *real* C-style if you still believe that the world
> can't deal with capitalized keywords. Either is a lot simpler than a
> whole bunch of special cases. Yeah, I don't have to remember them
> because of gofmt. Programming languages shouldn't depend on tools,
> they should make good sense by themselves.
> Just my $0.02 of course. Sorry for the rant, I don't mean to flame
> anyone. I mean to flame the topic.
> Cheers,
> Peter
> --
> Peter H. Froehlich <http://www.cs.jhu.edu/~phf/>
> Senior Lecturer | Director, Johns Hopkins Gaming Lab
> When we started working on Go, we were more concerned with semantics
> than syntax, but before long we needed to define the syntax in order
> to write programs. One syntactic idea we tried was to reduce the
> number of semicolons in the grammar, to make the source code cleaner-
> looking. We managed to get rid of many of them, but the grammar became
> clumsy and hard to maintain as we worked on the compiler, and we
> realized we had overreached. We backed up to a compromise that had
> optional semicolons in a few places, a couple of rules about where
> they go, and a tool (gofmt) to regularize them.
> Although we acclimated to the rules and were comfortable with them,
> once we launched it became clear that they were not really
> satisfactory. The compromise didn't seem to fit right with most
> programmers. The issue needed to be rethought.
> The language BCPL, an ancestor to B, which is an ancestor to C, had an
> interesting approach to semicolons. It can be summarized in two steps.
> First, the formal grammar requires semicolons in statement lists.
> Second, a lexical (not syntactic) rule inserts semicolons
> automatically before a newline when required by the formal grammar.
> In retrospect, had we thought of BCPL's approach at the time, we would
> almost certainly have followed its lead.
> We propose to follow it now.
> Appended to this mail is a formal specification of the proposed rules
> for semicolons in Go. They can be summarized much as in BCPL, but Go
> is a different language so the detailed rules differ; see the
> specification for the details. In short:
> - In the formal grammar, semicolons are terminators, as in C.
> - A semicolon is automatically inserted by the lexer if a line's
> last token is an identifier, a basic literal, or one of the following
> tokens: break continue fallthrough return ++ -- ) }
> - A semicolon may be omitted before a closing ) or } .
> The upshot is this: given the proposal, most required semicolons are
> inserted automatically and thus disappear from Go programs, except in
> a few situations such as for loop clauses, where they will continue to
> separate the elements of the clause.
> No more optional semicolons, no more rewriting; they're just gone. You
> can put them in if you want, but we believe you'll quickly stop and
> gofmt will throw them away.
> The code will look much cleaner.
> There are compatibility issues. A few things break with this proposal,
> but not many. (When processing the .go files under src/pkg with an
> updated parser, most files are accepted under the old and new rules.)
> By far the most important breakage is lexical string concatenation
> across newlines, as in
> "hello "
> "world"
> Since the language permits + to concatenate strings and constant
> folding is done by the compilers, this feature is simply gone from the
> language; use a + to concatenate strings. It's not a huge loss because
> `` strings can still span newlines.
> With the new rules, a semicolon is mistakenly inserted after the last
> element of a multi-line list if the closing parenthesis or brace is on
> a separate line:
> f(
> a,
> b
> )
> To avoid this issue, a trailing comma is now permitted in function
> calls and formal parameter lists, as is the case with composite
> literals already.
> A channel send spanning a newline can accidentally become a receive,
> as in
> a = b
> <-c
> Inserting a semicolon after the b changes the meaning from a non-
> blocking send to an assignment followed by a receive. For this
> transformation to mislead, however, the types of a, b and c must be
> very specific: interface{}, chan interface{} and chan. So a program
> might break but it is almost certain never to succeed incorrectly. We
> are aware of the risk but believe it is unimportant.
> A similar thing can happen with certain function calls:
> f()
> (g())
> If f() returns a function whose single argument matches the type of a
> parenthesized expression such as (g()), this will also erroneously
> change meaning. Again, this is so rare we believe it is unimportant.
> Finally, a return statement spanning a newline is broken up into two
> statements:
> return
> f()
> For this to miscompile, the return statement must be in a function
> with a single named result, and the result expression must be
> parseable as a statement.
> Gofmt's style already avoids all three problematic formattings.
> This proposal may remind you of JavaScript's optional semicolon rule,
> which in effect adds semicolons to fix parse errors. The Go proposal
> is profoundly different. First, it is a lexical model, not a semantic
> one, and we believe that makes it far safer in practice. The rules are
> hard and fast, not subject to contextual interpretation. Second, since
> very few expressions in Go can be promoted to statements, the
> opportunities where confusion can arise are also very few - they're
> basically the examples above. Finally, since Go is statically type-
> safe, the odds are even lower.
> Another language the proposal may evoke is Python, which uses white
> space for indentation. Again, the story here is very different.
> Program structure is not defined by white space. Instead, a much
> milder thing is happening: lists of statements, constants, etc. may be
> separated by placing them one per line instead of by inserting
> semicolons. That's all.
> Please read the proposal and think about its consequences. We're
> pretty sure it makes the language nicer to use and sacrifices almost
> nothing in precision or safety.
> Rolling out the change.
> Gofmt will be a big help in pushing out this change. Here is the plan.
> 1. Change gofmt to insert the + for string concatenation. Give it a
> flag to omit the semicolons but leave them in by default.
> 2. Reformat the tree with that gofmt: this inserts + for lexical
> string concatenation but otherwise is a no-op.
> 3. Update the compilers to insert semicolons. They should then accept
> gofmt output (with semicolons) and semicolon-free programs just fine.
> 4. Try things out, revising the specification and tools as required.
> 5. Once happy, make the gofmt default "no semicolons". Reformat the
> entire tree.
> The formal specification.
> The following changes are applied to the spec.
> 1) New semicolon rules:
> a) When the input is broken into tokens, a semicolon is automatically
> inserted into the token stream at the end of a non-blank line if the
> line's final token is:
> - an identifier or basic literal
> - one of the keywords break, continue, fallthrough or return
> - one of the tokens ++ -- ) ] }
> b) To allow complex statements to occupy a single line, a semicolon
> may be omitted before a closing ) or }.
> 2) The interpretation of comments is clarified:
> a) Line comments start with the character sequence // and continue
> through the next newline. A line comment acts like a newline.
> b) General comments start with the character sequence /* and continue
> through the character sequence */. A general comment that spans
> multiple lines acts like a newline, otherwise it acts like a space.
> 3) Replacements:
> a) All uses of StringLit are replaced by string_lit.
> b) All uses of StatementList are replaced by { Statement ";" }.
> 4) The following productions are simplified and always use semicolons
> as terminators. In idiomatic use, the semicolons are inserted
> automatically and thus won't appear in the source code.
> 5) The following productions permit optional commas. This enables
> multi-line constructions where the closing parenthesis or brace is on
> a new line if the last element is followed by a comma. The optional
> comma is only new for parameter lists and calls; composite literals
> permit it already.
On Dec 9, 6:49 pm, "Rob 'Commander' Pike" <r...@google.com> wrote:
> Here is a proposal.
I don't like it, simply because I've used a few languages with this
kind of feature before and it just plain messes with my flow. I'm not
going to argue it though.
>> I would like to clarify when a semicolon might be required. Presumably
>> when there are multiple statements on a line. I've constructed a
>> plausible test case for you.
> Yes, semicolons can be used to separate multiple
> statements on a single line. But the standard
> formatting will be to separate them with newlines instead.
Right. The point is that the newlines are already there. A tiny fraction of statements span lines. Let's make the default support the common case instead of requiring fly specks everywhere to enable the rare case.
> Do *you* really care? I mean is it really making your code a whole lot
> better or more enjoyable to write?
Honestly, it is. Since we started toying with this idea
I've had to go back in and add semicolons to every snippet
of code I've written in mail to this list, and even that has
gotten frustrating.
> Don't get me wrong, I really, really like Go. Heck, I do almost
> nothing but write Go code these days, for hours, and for fun. But I
> strongly believe that you're heading the wrong way by adding more
> rules to achieve a goal that's dubious in the first place.
Believe it or not, this removes rules. Robert played with
this in the parser and the language spec and was surprised
how much simpler things got. I am doing the same conversion
in the 6g compiler right now, and the dead code I'm cutting
away is one of the ugliest parts of the compiler. I'd
forgotten writing it, but boy is it ugly. And soon it will
be gone.
The status quo lets you omit semicolons in a handful of
magic places (basically, at top level and after certain
kinds of }, but not all, and not always). The new proposal
is dramatically more regular, much simpler to parse.
An earlier version of Go did single-file (as opposed to
single-package) compilation; if you wanted to refer to a
type or function in another file or even later in the same
file, you had to forward declare it, just like in C. For the
cross-file references you had to import your own package to
get access to the other files. In practice, this was fine,
it worked, we got used to it, but it was weird and a
stumbling block for new Go programmers. When we decided to
compile a package at a time and throw away all the forward
declarations, it took a couple weeks of work to make the
change in the compiler, because it was breaking a
fundamental architectural assumption in the compiler
(one-pass compilation). When we were done it felt like
maybe that wasn't such a great use of our time, since we'd
fallen behind on other things and hadn't really changed the
language that much. But looking back, it was time well
spent. Ken says it's one of his favorite features. He observes
that you don't realize quite how taxing the forward declarations
are in aggregate until they're gone, because each one costs next
to nothing.
I think we're going to feel the same way about semicolons in
a few months (and it's a much simpler change).
Syntax matters. Otherwise the world would be programming in
Modula-3 (or Oberon?) or Lisp.
> In this case, I'd suggest taking a page from the book of Python and
> making them both an error but allowing
> foo := (a +
> b -
> c)
> or
> foo := (a
> + b
> - c)
That's a good idea, but there are a couple places
in the language where semicolons are needed inside
parens (the factored import and declaration blocks);
having a special rule for them would make the change
depend on parser state instead of being purely lexical.
It's a very important distinction, both for predictability
and for simplicity of implementation.
> > In this case, I'd suggest taking a page from the book of Python and
> > making them both an error but allowing
> > foo := (a +
> > b -
> > c)
> > or
> > foo := (a
> > + b
> > - c)
> That's a good idea, but there are a couple places
> in the language where semicolons are needed inside
> parens (the factored import and declaration blocks);
> having a special rule for them would make the change
> depend on parser state instead of being purely lexical.
> It's a very important distinction, both for predictability
> and for simplicity of implementation.
On Thu, Dec 10, 2009 at 12:56 AM, John Asmuth <jasm...@gmail.com> wrote:
> How about allowing a \ to mean "end of line, but please, no semi-
> colon"? Pretty standard.
Backslash-newline is pretty standard in unix to mean "don't end my
line," but I think I prefer the elegance/simplicity of the proposed
new standard. The nice thing about not having the backslash is that
if you decide to join the two lines, you don't need to remove any
characters.
-- :: atomly ::
[ ato...@atomly.com : www.atomly.com : http://blog.atomly.com/ ...
[ atomiq records : new york city : +1.917.442.9450 ...
[ e-mail atomly-news-subscr...@atomly.com for atomly info and updates ...
> On Dec 9, 2009, at 4:56 PM, Ben Tilly wrote:
>> On Wed, Dec 9, 2009 at 3:49 PM, Rob 'Commander' Pike <r...@google.com> wrote:
>> [...]
>>> Appended to this mail is a formal specification of the proposed rules for
>>> semicolons in Go. They can be summarized much as in BCPL, but Go is a
>>> different language so the detailed rules differ; see the specification for
>>> the details. In short:
>>> - In the formal grammar, semicolons are terminators, as in C.
>>> - A semicolon is automatically inserted by the lexer if a line's last
>>> token is an identifier, a basic literal, or one of the following tokens:
>>> break continue fallthrough return ++ -- ) }
>>> - A semicolon may be omitted before a closing ) or } .
>>> The upshot is this: given the proposal, most required semicolons are
>>> inserted automatically and thus disappear from Go programs, except in a few
>>> situations such as for loop clauses, where they will continue to separate
>>> the elements of the clause.
>> Please, don't. I know that making semicolons optional is popular and
>> is done in a number of popular languages like JavaScript and Ruby,
>> however I don't like it.
>> Which do you prefer to read? Which makes the structure of the
>> calculation clearer at a glance?
>> Your semi-colon insertion rule would make the first style break
>> horribly, and would force the second style. Which I think it
>> significantly worse.
> It's funny. I typed a response to this defending the change
> saying that it does what you want. But it doesn't; I misread
> your mail because I assumed you disliked the first form.
> Because I do; the second is the one preferred by everyone here.
> Those trailing operators make it clear that we're not done yet,
> which makes the code more readable to my eyes.
Hmmm. I guess I have to think back to when I first encountered the
style in Perl Best Practices. I thought it sounded silly. Then I
tried it for a day. Then I never looked back. In fact I changed how
I format other languages as well along similar lines, and I've been
very happy with the change. (And frustrated by languages like Ruby
whose mostly-optional semicolon rules prevent that style.)
The difference is that eyes more easily scan down the left-hand column
than they do the right. When you are orienting yourself in unfamiliar
code this makes the structure clearer.
> So to answer your questions: Which do I prefer to read? Which is
> clearer? The second.
> I think these are minor points anyway. Again, it's about having a
> style, not what the style is. If the consequences of the rules
> were the other way around, I'd still be happy about them because
> I'd adjust quickly and not care. Gofmt saves all. Legislated taste
> trumps endless formatting arguments.
I've seen and made the "having a style matters more than what it is"
argument plenty of times myself. However I've also become convinced
over the last few years that some stylistic choices really are better.
Not a lot better. But noticeably better. And the effect of
consistently doing something noticeably better adds up over time.
If I walk into a code base that does things differently, the win is
sufficiently small that it is almost never worth the effort to change
the existing style. Even if you discount the certainty of political
battles over it. But given the choice I want the following:
- An indent of 2-4 spaces. Research indicates that people can read
and understand code better with an indent in that range than one which
is larger or smaller than that.
- When formatting lists, a standard that makes it not a syntax error
to copy the last line and add another. In a language which allows
trailing commas, this means with a , on the end. In a language
without, this means putting commas *before* list elements.
- Operators lined up on the left where they are easily scanned. This
is the one I just brought up.
Here is an example of a SQL formatting style that meets these rules
SELECT s.foo
, t.bar
, t.baz
FROM table1 s
JOIN table2 t
ON s.some_id = t.some_id
WHERE s.blat = 'some'
AND t.blot = 'condition'
;
Now this may look odd at first glance. But write a hundred complex
SQL queries that way and the rationale behind it becomes obvious.
Cheers,
Ben
PS I'll never understand programmers who run SQL on one long line.
You wouldn't want to read C, Java, Perl, JavaScript, etc that hasn't
been formatted, so why make a bad exception for SQL?
The purpose of semicolons in C/C++ is to allow multiple statements on
the same line and statement spanning several lines. Since those case
are the minority it means that most of the time semicolons are just
noise.
On Dec 9, 6:49 pm, "Rob 'Commander' Pike" <r...@google.com> wrote:
> No more optional semicolons, no more rewriting; they're just gone. You
> can put them in if you want, but we believe you'll quickly stop and
> gofmt will throw them away.
> The code will look much cleaner.
When I first read this I was all like, "WTF?" But now that I've had a
chance to think about it, I realize that was my Java/C/Obj-C etc
experience talking. Now I'm all like, "OK, let's do it."