Tuesday, December 17, 2013

Learning Go: Syntax Quirks

Whenever you approach a new language you'll stumble over things that are almost, but not quite, the same as the language you're currently using. Coming from a C and Java background, I've had several such experiences with Go. This post is about two of the syntactical oddities: things that result in compiler errors and not bugs. Future posts will be about things that show up at runtime.

Short-form Declarations

There are two ways to declare and initialize a variable in Go:

var x int = 10
y := 10

The first form is readily understandable to Java or C programmers, even though the syntax is strange: it defines a variable of type int, and assigns the value 10 to it. The second form relies on type inference to do almost the same thing.

I say “almost” because the literal 10 is a numeric constant, which is permitted to have arbitrary precision. And that means that you have to know what type the compiler will pick. Not really an issue, as short-form declarations are primarily used for function returns, and the compiler will quickly correct you if you assume incorrectly.

A somewhat more annoying quirk is re-assignment, as shown below:

x := 10
x, y := 20, 30      // this compiles
x := 30             // this doesn't

You're allowed to re-assign a variable that was formerly assigned using a short-form declaration only if you also assign a newly-declared variable at the same time. I suppose that the rationale is to prevent accidental overwrites of a variable, while still allowing a single “error” variable for function calls, but I think it just adds to the mental effort needed to understand a program. In some cases you can use “:=”, in others you must use a plain “=”; I prefer consistency.

Braces or Parentheses?

Like most C-family languages, Go uses braces to delimit blocks, and parentheses to delimit function arguments. What's confusing is that some things that you expect to be blocks or functions aren't. For example, the import declaration:

import (
    "fmt"
)

That certainly looks like it should take a block: it's a declaration, not a function call. But those are parentheses, not braces, and I have no idea why.

And going the other way, we have the initialization of a struct (this example copied from the Go Tour):

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    // ...

I'm always tripping over this one: I think it's a constructor function, but there aren't any constructors in Go. It's actually a composite literal, much like a Java array initializer.

No comments: