Send me an email!
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 aboutfmt.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 already¹.
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.
¹: The Go compiler refuses to compile a program with duplicate imports.
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.