What's happening in Go tip (2013-09-13)
This week we’ll concentrate on changes to go vet
and gofmt
, two important parts of Go’s tooling, as well as some
changes to cgo, some of which are especially important to users of OS X.
What’s happening ¶
Improved go vet ¶
Relevant CLs: CL 12936046, CL 12811043, CL 10895043, CL 13102043, CL 10409047
A number of changes make go vet
even more useful for checking the correctness of your code:
go vet
will now warn about recursive Stringer
implementations. A common mistake is writing code like the following:
func (t T) String() string {
return fmt.Sprintf("%v", t)
}
This will lead to infinite recursion because the %v
verb will also use the String()
method of T
. go vet
now
correctly warns about this.
Another printf
-related improvement is the detection of redundant calls to String()
and Error()
. Given a type T
that implements the Stringer
interface and a value t
of type T
, the following call to String()
is redundant:
fmt.Fprintf("%s", t.String())
go vet
will now suggest that this method call is redundant, because fmt
will already call it for us. The same
applies to Error()
.
One last printf
-related improvement is improved checking of types for various verbs.
-
%b
will no longer allow complex numbers, while%e
,%f
and%g
do. -
%p
will only accept types that actually represent pointers (maps, channels, slices,unsafe.Pointer
and functions/methods.) -
%s
will allow[]byte
in addition tostring
. -
Matching is recursive, which means that
map[K]V
and[]T
will be allowed if the verb matchesK
,V
andT
. That is,go vet
will for example not complain about
fmt.Printf("%d", []int{1, 2, 3})
The next change has nothing to do with printf
, but function comparison. In Go, functions and methods can be compared
against nil (with ==
and !=
). This check, however, only makes sense when using variables; named functions and
methods will never be nil. More importantly, Go 1.1 added method values, which can lead to code like the following,
which will compile but not do what you intended:
if t.SomeMethod != nil {
// ...
}
We wanted to compare the return value of SomeMethod()
with nil, but we forgot the parentheses. This way, the check
will always evaluate to true
. go vet
will now warn about this kind of pointless comparison.
The last go vet
change is about shadowing. One particularly nasty class of programmer mistakes in Go is unintentional
shadowing of variables, especially in combination with the :=
operator.
A new, optional, module that will check for probably unintentional shadowing has been added. It is still considered an
experimental feature and too noisy, which is why it needs to be enabled explicitly, by using go tool vet -shadow *.go
.
An overview of all kinds of shadowing it does and does not warn about can be found in the included test data. Many of
these errors are of stylistic nature to avoid programmer confusion and do not actually affect the program, but that
isn’t unusual, go vet
is often about good style as well as correctness.
Improved gofmt ¶
Relevant Cls: CL 12837044
CL 12837044 improves gofmt
’s handling of import statements. For one, it improves sorting of imports to also consider
import name and comment, in addition to the import path. The major improvement, however, is the automatic removal of
duplicate imports.
Given the following file
package main
import (
"fmt"
"fmt"
)
func main() { fmt.Println("test") }
gofmt
will remove the duplicate fmt
import and only leave one of them. This is especially interesting when using
editors that allow adding imports via a menu or keypress (for example go-mode in Emacs with C-c C-a
) because now you
can blindly add an import when you think you need it, without having to make sure that the import didn’t exist
already1.
gofmt
will make sure to always delete the right entries. Imports must have identical or no import names to be checked
for duplicates, and only imports with no attached comments will be removed.
Given
import (
"fmt" // bar
"fmt" // foo
a "foo"
b "foo"
b "foo"
)
gofmt
will only delete the duplicate b "foo"
import and leave the rest alone.
Changes to cgo ¶
Relevant CLs: CL 12350044, CL 13413047
An obvious trend in OS X is the preference of clang over gcc, to the point that Xcode 5 comes with a gcc
that symlinks
to clang. Because of that, cgo will use clang instead of gcc on OS X 10.8 and later.
The move to clang also requires Go to provide its own wrapper for C.malloc
because malloc
on OS X 10.9 is defined as
taking a ulong
instead of a size_t
– a change that doesn’t matter to C in this case, but does matter to Go because
of a stricter type system. A side-effect of this wrapper is that it implements a feature asked for in Issue 3403:
Crashing if C.malloc
(and by extension C.CString)
cannot allocate memory instead of returning nil.
And in case it wasn’t clear enough: If you’re using OS X 10.9 / Xcode 5, you do need Go tip or cgo will not work.
-
The Go compiler refuses to compile a program with duplicate imports. ↩︎