Go semantics can be fiddly
I've been writing a bunch of Go lately. It's generally nice since the compiler or my editor-run-linters whinge at me early on before the code does something but, but not always...
I'd made a change that caused the name err to not be first used so early in a long setup
function, so I changed this line:
db, err = sql.Open("postgres", dbURL)
to look like this:
db, err := sql.Open("postgres", dbURL)
thus causing err to be defined here and fixing the complaint about
err. Unfortunately, it also created a local shadowing of db, which is a
global database handle, which caused it now to not be initialised in a distant function that then panic'd with a
runtime error: invalid memory address or nil pointer dereference
In retrospect, it's fairly clear when reading the traceback what wasn't initialised, but it's also harder to
spot in practice, since I
was explicitly setting db, and I'd made a bunch of other seemingly innocuous code
changes at the same time. Luckily I found
this
where some other poor sod had done the same thing.
Interestingly, I'm using lots of linters for this project, and none of them complained about a pretty clear-to-the-computer uninitialised variable being used.
update: I think this is discussed in this bug, from 2010.