Dominik Honnef

What's happening in Go tip (2013-09-07)

Published:
Last modified:
by

Welcome back to yet another update on Go tip. We’ll be looking at another batch of smaller changes from all over the place; there’s something for everyone.

And if you’re waiting for some juicier changes, let me just say that they’re on my radar, but I am reserving them for the finale. Well, really for the big hole that the feature freeze will cause.

Also, I’m sorry for releasing this article a day late. I hope I didn’t ruin anyone’s Friday at work :-( – I will try to release the next article on time again.

What’s happening

This week we will be looking at:

Reusable Writer in compress/flate

Relevant CLs: CL 12953048, CL 13171046, CL 13435043, CL 12894043

Continuing the trend of less garbage, the Writers in compress/flate, compress/zlib and compress/gzip have a new Reset() method, which allows resetting a Writer’s internal state without needing to allocate new memory. According to issue 6138, this saves 1.4 MB of allocations per Writer you would have to create.

In a somewhat related change, a test in archive/zip has been brought down from 34 seconds to 0.23 seconds, by avoiding an allocation in archive/zip itself and by not using compress/flate in the test at all. While this hardly affects people who use archive/zip, it’s a welcome speedup to anyone who has to run Go’s entire test suite.

Improvements to text/template

Relevant CLs: CL 13091045, CL 13509046, CL 13327043

Two small additions to text/template (and, by extension, html/template) might make writing templates just a bit easier.

The first addition is {{else if}}, which can be used instead of {{else}}{{if}}. Naturally this also means one less level of nesting, so that this:

{{if A}}
  a
{{else}}
  {{if B}}
    b
  {{end}}
{{end}}

will turn into this:

{{if A}}
  a
{{else if B}}
  b
{{end}}

A welcome simplification!

The second addition are built-in comparison functions for basic types, that is booleans, (unsigned) integers, floats, complex numbers and strings. The eq (equality) comparison is special in that it accepts a variable number of arguments (at least two), comparing the first argument to all the other arguments in an OR relation. So {{eq arg1 arg2 arg3}} would be equivalent to arg1==arg2 || arg1==arg3. It is important to note that eq is an ordinary function, so there’s no short circuit and all arguments will be evaluated.

Furthermore, these functions are a bit more lax than the Go type system, allowing comparison between different sizes of the same type (e.g. int32 and int16), as well as different types with the same underlying type (e.g. type Foo int and int)

Here’s a table of the new functions as well as their equivalent Go syntax:

Operator Function
== eq
>= ge
> gt
<= le
< lt
!= ne

More control over database/sql’s connection pool

Relevant CLs: CL 10726044

A long awaited improvement (at least by some people) is more control over the connection pool managed by database/sql. Thanks to CL 10726044 it is now possible to limited the total number of simultaneous open connections, by using (*DB).SetMaxOpenConns(int).

It is an important addition to the already present SetMaxIdleConns. Limiting the number of idle connections wouldn’t prevent an unbounded number of connections to be created if they were needed, it would only close most of them once done. This could still lead to more connections than wanted, hitting database or resource limits.

By setting the maximum number of open connections, however, we ensure that we will never exceed that number of connections. Also, the maximum number of open connections can be bigger than the maximum number of idle connections, allowing bursts without keeping all connections around. This should remove the need for custom pooling, limits and semaphores in a lot of database code.

The netgo build tag

Relevant CLs: CL 7100050

Go binaries, if not using cgo, are usually statically linked. When importing the net package (directly or indirectly), however, one ends up with a dynamically linked binary, linking against libc. That’s because the net package, by default, uses cgo to use the system’s resolver, to support for example LDAP. The net package does come with a pure-Go resolver. Until now, it was only used when cgo wasn’t enabled, which means compiling the standard library (or at least net) as well as your own package with CGO_ENABLED=0. But that has the downside of disabling cgo for your entire project, which might not be desirable.

A new build tag, netgo, alleviates this problem by providing a way to build the standard library and your project with a pure-Go net package while still enabling cgo for other uses. In order to reinstall the standard library with netgo, you run

go install -a -tags netgo std

You also need to specify -tags netgo when building your own package, otherwise cgo will overrule and rebuild net every time you build your package. This does allow installing a netgo standard library as the default with cgo as a working alternative, but it also has the added cost of recompiling the net package every time you do not use the netgo tag.

Small tooling changes

There are two small changes to tooling that are worth mentioning.

Deletion of go doc

Relevant CLs: CL 12974043

The first is the deletion of go doc. Now, mind you, go doc is not the same as godoc. go doc accepts different (more limited) arguments than godoc and apparently the consensus was to remove it and focus on improving godoc instead. Issue 4849 kind of leads up to the deletion and CL 12974043 is ultimatively deleting it.

This change goes to show that Go’s compatibility promises only cover the language and standard library, not tools.

go get for git repositories

Relevant CLs: CL 12923043, some more I unfortunately do not have the numbers of.

If you ever used go get on a git repository and later went to look at the actual clone, you might have noticed that HEAD was in a detached state, and that every go get -u would put it back in detached state, with HEAD pointing at a specific commit on a remote branch.

And even though that isn’t technically a problem (you could still just check out the master branch), it would lead to confusion and occasional loss of data when one wasn’t aware of the fact.

In Go 1.2, however, go get will always create a “proper” (as in expected) clone, with an active master branch, and go get -u will use git pull and all its effects, such as aborting in case of conflicts or uncommitted changes. Old clones from before Go 1.2 will automatically be updated to the new format by go get -u.