If I can't format my programs the way I want, and I much prefer putting 
operators at the beginning of continuation lines for reasons mentioned on 
this page, and "Perl Best Practices", I simply won't use the language - at 
least not without implementing a pre-processor. Automatic semicolon 
inserting is the worst thing about JavaScript. Please make it optional in 
some way.

On Wednesday, December 9, 2009 at 6:49:52 PM UTC-5, Rob 'Commander' Pike 
wrote:
>
> Here is a proposal.
>
> - rob, for The Go Team
>
> *Introduction*
>
> 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.
>
>     StructType    = "struct"    "{" { FieldDecl  ";" } "}" .
>     InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
>
>     ImportDecl    = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
>     ConstDecl     = "const"  ( ConstSpec  | "(" { ConstSpec  ";" } ")" ) .
>     TypeDecl      = "type"   ( TypeSpec   | "(" { TypeSpec   ";" } ")" ) .
>     VarDecl       = "var"    ( VarSpec    | "(" { VarSpec    ";" } ")" ) .
>
>     SourceFile    = PackageClause ";" { ImportDecl ";" } { TopLevelDecl 
> ";" } .
>
>
> 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.
>
>     Parameters   =             "(" [ ParameterList  [ "," ] ] ")" .
>     CompositeLit = LiteralType "{" [ ElementList    [ "," ] ] "}" .
>     Call         =             "(" [ ExpressionList [ "," ] ] ")" .
>
>
> 6) The following productions are gone since they are not needed anymore 
> with the simplified productions outlined in 3) and 4).
>
>     StringLit
>     StatementList
>     Separator
>
>     FieldDeclList
>     MethodSpecList
>
>     ImportSpecList
>     ConstSpecList
>     TypeSpecList
>     VarSpecList
>
>
> 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
>         fmt.Print(prime, "\n")
>         ch1 := make(chan int)
>         go filter(ch, ch1, prime)
>         ch = ch1
>     }
> }
>
> func main() {
>     sieve()
> }
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to