Go 1.10
Table of contents
- Language changes
- Operating Systems support
- Tooling
- Runtime
- CGO support
- Debugging
- Assembly support
- Packages
- Closing notes
Introduction
Go 1.10 is the first major release after the announcement of the plans towards Go 2.0 at GopherCon 2017.
There are a number of exciting changes which I’ll cover below as well as some changes in the behavior of either tools or Go APIs which might result in an unexpected behavior compared to the previous change. I chose to flag these changes as “breaking change” in order to make it easier to identify them.
I’ve also tried to flag the CL that brought in the change as the discussions on them as well as the related changes in other CLs are a great source from learning how Go is organized, created, how features are reviewed, and hopefully inspire you to contribute to the language itself by either participating in reviews or issues or fixing issues (like Needs Investigation or Help Wanted).
Language changes
Let’s start with the language changes that Go 1.10 brings. There are only a couple of rather small changes, none of them significant.
First, you’ll be able to use an untyped constant as the index of an expression
x[1.0 << s]
where s
is the untyped constant
CL 60230
The second change is that you can now use method expressions like this
struct{io.Reader}.Read
, even if this is a rather unusual way to do so
CL 73233
Operating systems support
Moving on to the operating system support, Go 1.10 will be the last Go version to run on OS X 10.8 Mountain Lion, OS X 10.9 Mavericks, or on OpenBSD 6.0.
FreeBSD 10.3 is now required to run Go, up from FreeBSD 9.3 CL 64910
NetBSD is once again supported, but only in the unreleased version 8 and on
386
and amd64
. arm
support for NetBSD 8 was still broken at the time
of writing, see Issue 23073
On 32-bit MIPS systems you can now choose if you want emulation for floating
point instructions or not via a new environment variable settings
GOMIPS=hardfloat
(the default) and GOMIPS=softfloat
CL 37954
Tooling
The bigger changes in Go 1.10 come from the tooling improvements it brings. They dramatically improve the quality of life for testing in large and very large projects and pave the road towards Go 2.0.
Environment variables
Since Go 1.9,GOROOT
is inferred from the location of the go
tool binary
by default. However, if your application relied on that value at runtime via
runtime.GOROOT()
there was a bug which prevented it have the correct
location. As of Go 1.10+ this bug was fixed and you can now use it as expected
CL 61310
A couple of new environment variables were added to the go
command.
GOTMPDIR
will allow you to configure where the temporary files created by Go
during compilation of your applications are stored. The default path is the same
as in the previous Go versions, the operating system’s temporary files
directory. The other new environment variable is GOCACHE
allows you to
control where the go
command will store the cached information that’s reused
in future builds CL 75475
go build
go build
can now detect changes in files on a source code level rather than
rely on timestamps, which means that it will be more accurate in rebuilding the
packages that have changed. In turn, this means that you will now be able to
drop the usage of -a
flag, which was previously used to force Go to rebuild
packages in certain conditions.
Changes are coming to the -asmflags
, -gcflags
, -gccgoflags
, and
-ldflags
flags. They will not be applied automatically to the list of all
packages as before but only to the direct package that’s being specified in the
build
command. You can still achieve the same functionality as before using
the new special syntax for these flags, -ldflags=pattern=flags
such as:
go build -ldflags=cmd/gofmt=-X=main.version=1.2.3 cmd/...
. This command
allows you to build all the /cmd/...
packages but it will apply the
-ldflags=-X=main.version=1.2.3
flag only to the cmd/gofmt
package
CL 76551
To further speed up the builds, go build -i
will not be necessary since now
the build tool will have its own cache for build steps that do not do the
install step, such as go install
or go get
. This means that you’ll be
able to switch between branches or experiment a lot more with the code without
having to invoke go install
or go build -i
but just go build
.
Are you a Windows user? Now you can use c-shared as a target for your libraries, thanks to CL 69091.
go install
go install
also received some changes. Now it will install only the
explicitly mentioned packages but not their dependencies. To restore the
previous behaviour, you’ll need to use this command as go install -i
CL 75850
This change as well as upcoming changes is significant if your tools depend on
the packages to be installed in $GOPATH/pkg
and always be fresh, with
additional changes being required in order to restore the old behaviour.
go test
Speaking of caching, go test
has seen a lot of changes as well. One of the
most important is that go test
will now cache the results of the tests if
they meet certain criteria such as:
- the test executable and command line match a previous run
- the files and environment variables used by that run have not changed
- the results are successful
- the
go test
command received a list of packages to test,go test ./...
for example - the test command line uses a subset of the test flags,
-cpu
,-list
,-parallel
,-run
,-short
, and-v
When the above conditions are met, the first run will produce the output as
expected then subsequent runs will simply reuse that output. The run time of the
tests will also notify that the cached output is used, by displaying (cached)
instead of the original test run time.
You can always force the tests to run by specifying the flag -count=1
, this
being considered the idiomatic way to handle this requirement. As a recap, the
-count
flag allows you to specify how many times a test or a benchmark runs.
This change is covered in CL 75631.
The second important change to go test
is that now a subset of go vet
checks will run before the tests run in order to detect issues with your code.
These checks will be treated as build failures in case any of them will produce
any result. Only very high accuracy checks are included in this step. To disable
this new behavior you’ll need to provide the -vet=off
flag to the go test
command CL 74356
The coverage profile of tests can now be created when running the tests against
multiple packages, which was a highly requested feature. Combined with the new
way to use the -coverpkg
flag, it means you’ll be able to get the coverage
for all the packages tested packages as well as their dependencies when multiple
packages are being tested by running
go test -coverpkg=all -coverprofile cover.out ./...
CL 76875 and
CL 76876
Test binaries will now always write to stdout
when invoked via go test
whereas before stderr
could have been used sometimes
CL 76871
Tests running in parallel will now be better delimited by having PAUSE
and
CONT
as status update lines when running with -v
flag. This change
allows tooling to better interpret the start and stop of parallel tests. The
-failfast
flag now will stop testing immediately on the first failure, with
the caveat that parallel tests are still allowed to continue until they finish
CL 74450
Finally, go test -json
will now output the format of the tests in json so
that tooling such as IDEs can better present the results of the test. There is
also a new command, go tool test2json
that will produce convert the test
output to json CL 76873 and
CL 76872
gofmt
Another set of tooling changes in Go 1.10 come from gofmt
as it received
a few updates. First, three index slice expressions containing complex
expressions are now always formatted as slice[start+1 : stop : capacity]
CL 67633
The second change is that single-method interface literals written on a single line, which are sometimes used in type assertions, are no longer split onto multiple lines CL 66130
The third one is that if a composite literal would include a comment and only comments, then the comment(s) will now be indented CL 74232
If you use gofmt
in your CI environment, you will see some failures because
of these changes. The official position is that gofmt
is not covered by the
same set of compatibility promises as Go 1 itself, so these are not “breaking
changes” but it’s rather a constant evolving specification, which can suffer
changes on each new Go release. The recommendation is not to have gofmt
enforced in the CI or have everyone use the same binary version for the
application that formats your source code as well as checks it in the CI system.
A good news is that now all flags supported by gofmt
are supported by
go fmt
as well.
go fix
go fix
now replaces imports from golang.org/x/net/context
with
context
which will help you migrate your code to a Go 1.9+ compatible code
by running go tool fix -r context your/package
CL 58590
pprof
Go 1.10 will also bring an update to the pprof
tool. This brings a host of
improvements, among which an updated UI featuring a flame graph representation
of the profiling data CL 75870
Runtime
Go’s runtime received a few updates, with the first one I’ll cover being done
on how the LockOSThread
and UnlockOSThread
mechanism works. If before,
in nested calls, UnlockOSThread
would need to be called only once to unlock
the thread, now it will need to be called as many times as LockOSThread
was
called CL 45752
You may have noticed the <autogenerated>
frame (line) in the stack traces
before. This is now hidden, unless a panic or other issue happens in it. This
also means that if your code would call runtime.Caller
with a certain number
of skip frames, then this change will be a “breaking change” in its behaviour as
the <autogenerated>
frames will not be counted there either
CL 45412
Another important change in the Go runtime is the introduction of soft and hard goals (limits) for garbage collection CL 59970
The soft limit is the current value of the GOGC while the hard limit is 10% higher than the soft limit. Heavy GC reliant applications (so far only benchmarks) shows that there’s an increase in the heap size of the application.
CGO support
CGO support has also received updates, with C typedefs such as typedef X Y
now which means you’ll be able to use C.X
and C.Y
interchangeably in Go
now, as if they would be Go aliases, type X = Y
CL 62670
Another welcomed change when working with C and Go is that you can now pass Go
strings directly to C. This is done by declaring a C function in a Go file with
a parameter type of the special type name _GoString_
. To access the string
length, you’ll need to call size_t _GoStringLen(_GoString_ s)
an in order to
get the pointer to the string contents, you’ll need use
const char *_GoStringPtr(_GoString_ s)
CL 70890
Some C types that were previously mapped to a pointer type in Go are now mapped
to uintptr
type. A couple of these types are CFTypeRef
in Darwin’s
CoreFoundation framework and the jobject
in Java’s JNI interface. You’ll
need to initialize the values for the affected types with 0
instead of
nil
This is a breaking change but thankfully you can fix this quickly and
automatically by running go tool fix -r cftype your/package
or
go tool fix -r jni your/package
CL 66332
and CL 81876
Debugging
Debugging support has also been improved in the latest release which should make your debugging experience via Delve even better than before. And as a reminder, Delve is most likely integrated with your favorite code editor.
Assembly support
Assembly support got better as well, with a host of new instructions being added. Most important changes are under amd64 platform with 359 new instructions including the full AVX, AVX2, BMI, BMI2, F16C, FMA3, SSE2, SSE3, SSSE3, SSE4.1, and SSE4.2 extension sets.
Packages
Changes in the various standard library packages:
bufio - the new Reader.Size and Writer.Size and methods report the Reader or Writer’s underlying buffer size CL 75150
bytes - the Fields, FieldsFunc, Split, and SplitAfter each already returned slices pointing into the same underlying array as its input. Go 1.10 changes each of the returned subslices to have capacity equal to its length, so that appending to a subslice will not overwrite adjacent data in the original input. This is also a “breaking change” in the behavior of these functions and you might need to update your code.
crypto/tls - the TLS server now advertises support for SHA-512 signatures when using TLS 1.2. The server already supported the signatures, but some clients would not select them unless explicitly advertised CL 74950
crypto/x509 - leaf certificate validation now enforces the name constraints for all names contained in the certificate, not just the one name that a client has asked about. Extended key usage restrictions are similarly now checked all at once. As a result, after a certificate has been validated, now it can be trusted in its entirety. It is no longer necessary to revalidate the certificate for each additional name or key usage CL 62693
database/sql/driver - drivers that want to construct a
sql.DB
for their clients can now implement theConnector
interface and call the newsql.OpenDB
function, instead of needing to encode all configuration into a string passed tosql.Open
. Drivers that want to parse the configuration string only once persql.DB
instead of once persql.Conn
, or that want access to eachsql.Conn
’s underlying context, can make theirDriver
implementations also implementDriverContext
’s newOpenConnector
method. Drivers that implementExecerContext
no longer need to implementExecer
; similarly, drivers that implementQueryerContext
no longer need to implementQueryer
. Previously, even if the context-based interfaces were implemented they were ignored unless the non-context-based interfaces were also implemented. To allow drivers to better isolate different clients using a cached driver connection in succession, if aConn
implements the newSessionResetter
interface,database/sql
will now callResetSession
before reusing theConn
for a new clientencoding/json - the Decoder adds a new method DisallowUnknownFields that causes it to report inputs with unknown JSON fields as a decoding error. The default behavior has always been to discard unknown fields. CL 27231 Unmarshal can no longer decode into fields inside embedded pointers to unexported struct types, because it cannot initialize the unexported embedded pointer to point at fresh storage. Unmarshal now returns an error in this case. This means you may need to update your code or a “breaking change” will happen, which could be hidden if the code is not properly handling errors CL 76851
text/template and html/template - the new actions
{{break}}
and{{continue}}
break out of the innermost{{range ...}}
loop, like the corresponding Go statements CL 66410math/rand - the new math/rand.Shuffle function and corresponding math/rand.*Rand.Shuffle method shuffle an input sequence CL 51891
math - the new functions Round and RoundToEven round their arguments to the nearest floating-point integer;
Round
rounds a half-integer to its larger integer neighbor (away from zero) whileRoundToEven
rounds a half-integer to its even integer neighbor CL 43652 and CL 61211net - the
Conn
andListener
implementations in this package now guarantee that whenClose
returns, the underlying file descriptor has been closed. In earlier releases, if theClose
stopped pending I/O in other goroutines, the closing of the file descriptor could happen in one of those goroutines shortly afterClose
returned.TCPListener
andUnixListener
now implementsyscall.Conn
, to allow setting options on the underlying file descriptor usingsyscall.RawConn.Control
. TheConn
implementations returned byPipe
now support setting read and write deadlines. TheIPConn.ReadMsgIP
,IPConn.WriteMsgIP
,UDPConn.ReadMsgUDP
, andUDPConn.WriteMsgUDP
, methods are now implemented on Windowsnet/http - on the client side, an HTTP proxy, most commonly configured by
ProxyFromEnvironment
, can now be specified as anhttps://
URL, meaning that the client connects to the proxy over HTTPS before issuing a standard, proxied HTTP request. Previously, HTTP proxy URLs were required to begin withhttp://
orsocks5://
. On the server side,FileServer
and its single-file equivalent ServeFile now applyIf-Range
checks toHEAD
requests.FileServer
also now reports directory read failures to theServer
’sErrorLog
. The content-serving handlers also now omit theContent-Type
header when serving zero-length content.ResponseWriter
’sWriteHeader
method now panics if passed an invalid (non-3-digit) status code.Redirect
now sets the Content-Type header before writing its HTTP responsenet/url -
ResolveReference
now preserves multiple leading slashes in the target URL. Previously it rewrote multiple leading slashes to a single slash, which resulted in thehttp.Client
following certain redirects incorrectlyos -
File
adds new methods SetDeadline, SetReadDeadline, and SetWriteDeadline that allow setting I/O deadlines when the underlying file descriptor supports non-blocking I/O operations CL 71770 The definition of these methods matches those innet.Conn
. Also matchingnet.Conn
,File
’sClose
method now guarantee that whenClose
returns, the underlying file descriptor has been closedstrings - a new type Builder is a replacement for
bytes.Buffer
for the use case of accumulating text into a string result. TheBuilder
’s API is a restricted subset ofbytes.Buffer
’s that allows it to safely avoid making a duplicate copy of the data during the String method CL 74931unicode - the
unicode
package and associated support throughout the system has been upgraded from version 9.0 to Unicode 10.0, which adds 8,518 new characters, including four new scripts, one new property, a Bitcoin currency symbol, and 56 new emoji
A lot more packages have received changes but I’ve tried to keep the list to a minimum. To view the full list of changes, you can read this the Draft Release Notes.
Closing notes
Due to the vast amount of changes both in compiler and in runtime, some workloads are expected to perform better as of Go 1.10. However, I highly recommend that you grab the latest Go 1.10 release, 1.10 Beta 1 and test it on your workloads, run the tests against the new Go version and help the Go team identify issues before Go 1.10 lands in February. There are a few weeks where even just running the test / benchmark suite could make the difference. And Go 1.10 Beta 1 is also available as a Docker container so you can minimize the impact it has on your system.
If you want to stay up to date with the developments of Go, I recommend following @golang_cls Twitter account which provides a curated list of interesting commits as they are added to Go.
If you want to talk more about Go, its evolution, and what’s next for Go, tweet me, or meet me at Gophercon Iceland!
Finally, I would like to thank the Go Team and all contributors that helped Go reach 1.10 and I look forward to what the future holds.
A big thank you goes to Russ Cox and the team that created the initial draft documentation which this article uses / reuses a lot.
Errata:
The initial version of this article incorrectly mentioned a change about how GOROOT is handled. Thank you to Dominik Honnef for reporting this.