A TEXT POST

Go Multiple Return Values

I love the go programming language, but it’s not without problems.

I just encountered a little annoyance involving multiple return values. Here’s a very common pattern in go code:

db, err := sql.Open("sqlite3", "./foo.db")

In this example, sql.Open returns two values, one which is the database object and the other to represent any possible errors. The := syntax declares variables using type inference. It is the idiomatic way to declare all local variables. Here’s where the problem arrises:

var db *sql.DB

func initialize() {
    db, err := sql.Open("sqlite3", "./foo.db") // broken
    if err != nil {
        log.Fatal("Could not open database")
    }
}

The issue is that := is redeclaring both variables, shadowing the global db. This isn’t necessarily obvious at first look because := does allow for redeclaration of variables in the same scope, provided that at least on of the variables being declared is new.

var x int = 9
x, y := 5, 7

This code compiles and works as expected, however, the following does not:

var x int = 9
var x, y int = 5, 7

This makes it relatively easy to be careless and move the declaration to a higher scope:

var x int = 9

func main() {
    x, y := 5, 7
    other()
}

func other() {
    fmt.Printf("%d\n", x)
}

This prints “9”, not “5” as might be expected.

The cleanest way to fix this is to declare y on its own and then use the reassignment operator:

var x int = 9

func main() {
    var y int
    x, y = 5, 7
    other()
}

func other() {
    fmt.Printf("%d\n", x)
}

This code will, in fact, print “5” and not “9”.

Fortunately, I noticed this non-obvious behavior when I encountered it and tested it out with the go playground. Had I not noticed it, and had my project been slightly larger, it might have taken me a little while to figure out why my global db object wasn’t getting initialized.

  1. henry-ren reblogged this from adrusi
  2. adrusi posted this