The State of Go Where we are in February 2016 Francesc Campoy Gopher at Google

Time flies Go 1.4 is one year old (happy birthday!) Go 1.5 is already 6 months old! Go 1.6 to be released sometime in February. Go 1.6 Candidate Release 1 was released on January 28th 2

Notes The slides are available on talks.golang.org/2016/state-of-go.slide Most of the code examples won't run except locally and using Go 1.6. The playground still runs Go 1.5. 3

Agenda Changes since Go 1.5: the language

the standard library

the runtime

the tooling

the community 4

Changes to the language 5

Changes to the language None. This is a feature. 6

Changes to the standard library 7

Changes to the standard library A couple of new things, in order of excitement. net/http {text,html}/template sort Also more speed and fewer bugs. 8

net/http If: you're using HTTPS and Go 1.6 you're using HTTP/2! 9

HTTP/2 At a high level, HTTP/2: is binary, instead of textual

is fully multiplexed, instead of ordered and blocking

can therefore use one connection for parallelism

uses header compression to reduce overhead

allows servers to “push” responses proactively into client caches http2.golang.org/gophertiles 10

text/template Imagine that given a slice of strings: []string{"one", "two", "three"} We want to write a template that will generate: <ul> <li>one</li> <li>two</li> <li>three</li> </ul> What template would you write? 11

text/template: first try Naturally, I write this: // +build ignore,OMIT package main import ( "html/template" "log" "os" ) var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> `)) func main() { err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"}) if err != nil { log.Fatal(err) } } But unfortunately it's not exactly what I want! 12

text/template: let's fix it We need to be careful with the line breaks. // +build ignore,OMIT package main import ( "html/template" "log" "os" ) var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range .}}<li>{{.}}</li> {{end}}</ul> `)) func main() { err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"}) if err != nil { log.Fatal(err) } } This works now, but ... I don't really like my code! 13

text/template: meet {{- and -}} Go 1.6 brings two new delimiters: {{-

-}} Similar to {{ and }} , but all white space on the - side will be trimmed. The template: {{23 -}} < {{- 45}} generates: 23<45 14

text/template: back to our problem We can now have: the result we expected

without sacrificing the readability of our templates. // +build ignore,OMIT package main import ( "html/template" "log" "os" ) var tmpl = template.Must(template.New("tmpl").Parse(` <ul> {{range . -}} <li>{{.}}</li> {{end -}} </ul> `)) func main() { err := tmpl.Execute(os.Stdout, []string{"one", "two", "three"}) if err != nil { log.Fatal(err) } } 15

text/template: the block action Go 1.6 brings also a new action named block . Let's see what it is useful for. 16

Factoring out repetition in templates Both <ul> share the same structure. {{define "presentation"}} Authors: <ul> {{range .Authors}} <li>{{.}}</li> {{end}} </ul> Topics: <ul> {{range .Topics}} <li>{{.}}</li> {{end}} </ul> {{end}} Templates can be used to avoid repetition. 17

Factoring out repetition with templates (cont.) We can define a new template: {{define "list"}} <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> {{end}} And use it where needed: {{define "presentation"}} Authors: {{template "list" .Authors}} Topics: {{template "list" .Topics}} {{end}} 18

Factoring out repetition with templates (cont.) We can parse that template and execute it. // +build ignore,OMIT package main import ( "html/template" "log" "os" ) const tmplText = ` {{define "list"}} <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> {{end}} {{define "presentation"}} Authors: {{template "list" .Authors}} Topics: {{template "list" .Topics}} {{end}} ` type Presentation struct { Authors []string Topics []string } func main() { p := Presentation{ Authors: []string{"one", "two", "three"}, Topics: []string{"go", "templates"}, } tmpl := template.Must(template.New("presentation").Parse(tmplText)) err := tmpl.Execute(os.Stdout, p) if err != nil { log.Fatal(err) } } 19

Template redefinition We made also our template easier to reuse, as we can redefine list . // +build ignore,OMIT package main import ( "html/template" "log" "os" "strings" ) const tmplText = ` {{define "list"}} <ul> {{range .}} <li>{{.}}</li> {{end}} </ul> {{end}} {{define "presentation"}} Authors: {{template "list" .Authors}} Topics: {{template "list" .Topics}} {{end}} ` type Presentation struct { Authors []string Topics []string } func main() { p := Presentation{ Authors: []string{"one", "two", "three"}, Topics: []string{"go", "templates"}, } tmpl := template.Must(template.New("presentation").Parse(tmplText)) tmpl = tmpl.Funcs(template.FuncMap{"join": strings.Join}) tmpl = template.Must(tmpl.Parse(`{{define "list"}} {{join . " | "}} {{ end}}`)) err := tmpl.Execute(os.Stdout, p) if err != nil { log.Fatal(err) } } 20

Meet the block action The block action defines and executes a template in place. {{define "presentation"}} Authors: {{block "list" .Authors}} <ul> {{- range .}} <li>{{.}}</li> {{- end}} </ul> {{end}} Topics: {{template "list" .Topics}} {{end}} That template defined by block can be: referenced later by the same template,

redefined with define . 21

Why do we need it? It is more compact when we're not factoring out repetition,

but we need to provide an extension point. We can make the following template more compact with block . {{define "content" .}} <h1>{{.Heading}}<h1> <p>{{.Content}}</p> {{end}} {{define "page"}} <title>{{.Title}}</title> <body> {{template "content" .}} </body> {{end}} 22

Why do we need it? (cont.) We can make the following template more compact with block . {{define "page"}} <title>{{.Title}}</title> <body> {{block "content" .}} <h1>{{.Heading}}<h1> <p>{{.Content}}</p> {{end}} </body> {{end}} And still easily redefine content . 23

sort.Sort is faster Sort sorts your data by calling Less , Swap , and Len . We reduced the number of comparisons and swaps by about 10%. Sort []int with Go 1.5 BenchmarkSort_1-4 20000000 67.2 ns/op BenchmarkSort_10-4 10000000 227 ns/op BenchmarkSort_100-4 500000 3863 ns/op BenchmarkSort_1000-4 30000 52189 ns/op Sort []int with Go 1.6 BenchmarkSort_1-4 20000000 64.7 ns/op BenchmarkSort_10-4 10000000 137 ns/op BenchmarkSort_100-4 500000 2849 ns/op BenchmarkSort_1000-4 30000 46949 ns/op 24

sort.Sort is faster - plot 25

Sort order and sort.Stable Reminder: sort.Sort is not a stable sort. // +build ignore,OMIT package main import ( "fmt" "sort" "strings" ) type byLength []string func (b byLength) Len() int { return len(b) } func (b byLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) } func (b byLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func main() { values := []string{"ball", "hell", "one", "joke", "fool", "moon", "two"} sort.Sort(byLength(values)) fmt.Println(strings.Join(values, "

")) } Use sort.Stable : // +build ignore,OMIT package main import ( "fmt" "sort" "strings" ) type byLength []string func (b byLength) Len() int { return len(b) } func (b byLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) } func (b byLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func main() { values := []string{"ball", "hell", "one", "joke", "fool", "moon", "two"} sort.Stable(byLength(values)) fmt.Println(strings.Join(values, "

")) } 26

Minor changes too many to discuss: find them here 27

Let's just discuss one time.Parse is smarter! // +build ignore,OMIT package main import ( "fmt" "time" ) func main() { days := []string{"2015 Feb 29", "2016 Feb 29", "2017 Feb 29"} fmt.Println("Are these days valid?") for _, day := range days { _, err := time.Parse("2006 Jan 2", day) fmt.Printf("%v -> %v

", day, err == nil) } } 28

Changes to the runtime 29

Detection of concurrent map accesses Detection of unsafe concurrent access to maps. // +build ignore,OMIT package main import ( "fmt" "sync" ) func main() { const workers = 100 // what if we have 1, 2, 25? var wg sync.WaitGroup wg.Add(workers) m := map[int]int{} for i := 1; i <= workers; i++ { go func(i int) { for j := 0; j < i; j++ { m[i]++ } wg.Done() }(i) } wg.Wait() fmt.Println(m) } Outputs: fatal error: concurrent map read and map write fatal error: concurrent map writes 30

Does it make it slower? No! Let's benchmark it - with a correct solution. func count(n int) { var wg sync.WaitGroup wg.Add(n) m := map[int]int{} var mu sync.Mutex for i := 1; i <= n; i++ { go func(i int) { for j := 0; j < i; j++ { mu.Lock() m[i]++ mu.Unlock() } wg.Done() }(i) } wg.Wait() } 31

Benchmark results Go 1.4 - GOMAXPROCS = 4 BenchmarkCount_1 1000000 1862 ns/op BenchmarkCount_10 100000 21214 ns/op BenchmarkCount_100 1000 1602507 ns/op BenchmarkCount_1000 10 141712948 ns/op Go 1.5 - GOMAXPROCS = 4 BenchmarkCount_1-4 2000000 867 ns/op BenchmarkCount_10-4 200000 6909 ns/op BenchmarkCount_100-4 1000 1025092 ns/op BenchmarkCount_1000-4 20 94093719 ns/op Go 1.6 - GOMAXPROCS = 4 BenchmarkCount_1-4 2000000 750 ns/op BenchmarkCount_10-4 200000 6582 ns/op BenchmarkCount_100-4 2000 1113790 ns/op BenchmarkCount_1000-4 20 87998054 ns/op 32

Benchmark results plot 33

Benchmark results Go 1.4 - GOMAXPROCS = 1 BenchmarkCount_1 100000 1370 ns/op BenchmarkCount_10 20000 8622 ns/op BenchmarkCount_100 500 362725 ns/op BenchmarkCount_1000 50 31378803 ns/op Go 1.5 - GOMAXPROCS = 1 BenchmarkCount_1-4 2000000 776 ns/op BenchmarkCount_10-4 200000 6288 ns/op BenchmarkCount_100-4 3000 345037 ns/op BenchmarkCount_1000-4 50 31751625 ns/op Go 1.6 - GOMAXPROCS = 1 BenchmarkCount_1-4 2000000 767 ns/op BenchmarkCount_10-4 200000 6041 ns/op BenchmarkCount_100-4 5000 329328 ns/op BenchmarkCount_1000-4 50 30176034 ns/op 34

Benchmark results plot 35

Garbage Collector in Go 1.5 At GopherCon 2015 Rick Hudson gave a presentation about the Go 1.5 low latency collector 36

Garbage Collector in Go 1.6 At QCon SF in November Rick Hudson gave an updated presentation which showed this comparison of Go 1.5 to the upcoming Go 1.6 Yes, that is gigabytes on the X axis 37

Garbage Collector on tip Right now it's even better! 38

People loved it with Go 1.5 original tweet 39

People love it even more with Go 1.6 original tweet 40

Oops original tweet and video 41

New ports Experimental ports to Linux on 64-bit MIPS (linux/mips64 and linux/mips64le). Experimental port to Android on 32-bit x86 (android/386). On Linux on little-endian 64-bit PowerPC (linux/ppc64le), Go 1.6 now supports cgo with external linking and is roughly feature complete. On NaCl, Go 1.5 required SDK version pepper-41. Go 1.6 adds support for later SDK versions. 42

Changes to the tooling 43

The cgo tool Go is garbage collected, can C and Go share memory? In short: Go can pass a pointer to C

the referenced memory can't have pointers to Go allocated memory

C can't keep pointers to the memory after the call returns In more detail: the cgo docs. This is checked by the runtime at execution. You could disable the checks, but you probably shouldn't. 44

Sharing pointers between Go and C package main /* int fn(void* arg) { return arg == 0; } */ import "C" import "unsafe" type T struct{ a, b int } type X struct{ t *T } func main() { t := T{a: 1, b: 2} C.fn(unsafe.Pointer(&t)) // correct x := X{t: &t} C.fn(unsafe.Pointer(&x)) // incorrect } Outputs: panic: runtime error: cgo argument has Go pointer to Go pointer 45

The go tool GO15VENDOREXPERIMENT is now enabled by default. How does it work? /home/user/gocode/ src/ server-one/ main.go (import "github.com/gorilla/mux") server-two/ main.go (import "github.com/gorilla/mux") vendor/ github.com/ gorilla/ mux/ ... server-one uses the mux package in $GOPATH/src/github.com/gorilla/mux . server-two uses the mux package in vendor . 46

Vendoring demo 47

go doc Go 1.5 added the possibility of searching by name go doc math Pi Go 1.6 defines priority of packages with import paths with less elements. Non vendored packages appear first. 48

go vet Go vet warns if the code prints a function instead of its result. package main import "fmt" func foo() string { return "bar" } func main() { fmt.Printf("%v", foo) } go vet output: main.go:8: arg foo in Println call is a function value, not a function call The warning can be removed using %p in the format string. 49

The community 50

The community Code of Conduct announced on November 24th 2015 Go meetups: go-meetups.appspot.com Women Who Go - 7 chapters already! www.womenwhogo.org 51

Go 1.6 release party, February 17th Go 1.6 ships soon! Go meetups are organising to hold a release party on the 17th of February. Join the party!!! 53