Should I Go?

7 February 2013

Alexander Surma

Voxelbrain, GDG Berlin Golang

Hype

You may have heared of Go. It’s been getting a lot of attention and
therefore hate:

(I’m looking at you, Hacker News)

Go is boring

… and I like it. It’s become my main general purpose language.

Go is boring

Designed (mainly) for:

What is Go?

An open source (BSD licensed) project:

OOP but different

Go is Object Oriented, but not in the usual way.

The result: simple pieces connected by small interfaces.

Go is about concurrency

Go provides CSP-like concurrency primitives.

The result: comprehensible, reasonable concurrent code .

Code

Hello, go

package main

import "fmt"

func main() {
    fmt.Println("Hello, go")
}

Hello, net

package main

import (
    "fmt"
    "log"
    "net"
)

const listenAddr = "localhost:4000"

func main() {
    l, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    for {
        c, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Fprintln(c, "Hello!")
        c.Close()
    }
}

Interfaces

Did we just use Fprintln to write to a net connection?

That's because a Fprintln writes to an io.Writer, and net.Conn is an io.Writer.

        fmt.Fprintln(c, "Hello!")
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
type Writer interface {
    Write(p []byte) (n int, err error)
}
type Conn interface {
    Read(b []byte) (n int, err error)
    Write(b []byte) (n int, err error)
    Close() error
    // ... some additional methods omitted ...
}

An echo server

package main

import (
    "io"
    "log"
    "net"
)

const listenAddr = "localhost:4000"

func main() {
    l, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    for {
        c, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }
        io.Copy(c, c)
    }
}

A closer look at io.Copy

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the first error encountered while copying, if any.
func Copy(dst Writer, src Reader) (written int64, err error)
type Writer interface {
    Write(p []byte) (n int, err error)
}
type Reader interface {
    Read(p []byte) (n int, err error)
}
type Conn interface {
    Read(b []byte) (n int, err error)
    Write(b []byte) (n int, err error)
    Close() error
    // ... some additional methods omitted ...
}

Goroutines

Goroutines are lightweight threads that are managed by the Go runtime. To run a function in a new goroutine, just put "`go`" before the function call.

package main

import (
    "fmt"
    "time"
)

func main() {
    go say("I'm last", 3)
    go say("I'm middle", 2)
    go say("I'm first", 1)
    time.Sleep(4 * time.Second)
}

func say(text string, secs int) {
    time.Sleep(time.Duration(secs) * time.Second)
    fmt.Println(text)
}

A concurrent echo server

package main

import (
    "io"
    "log"
    "net"
)

const listenAddr = "localhost:4000"

func main() {
    l, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    for {
        c, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }
        go io.Copy(c, c)
    }
}

Closures and return values

package main

import "fmt"

func doAndPrint(x, y string, f func(x, y string) (string, string)) {
    x, y = f(x, y)
    fmt.Println(x, y)
}

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    doAndPrint("x", "y", swap)
}

Channels

package main

import (
	"fmt"
)

func Generate() <-chan int {
	ch := make(chan int)
	go func() {
		for i := 2; ; i++ {
			ch <- i
		}
	}()
	return ch
}

func Filter(in <-chan int, prime int) <-chan int {
    out := make(chan int)
    go func() {
        for {
            i := <-in
            if i%prime != 0 {
                out <- i
            }
        }
    }()
    return out
}

func main() {
    primes := Generate() // 2, 3, 4, 5, …
    for i := 0; i < 10; i++ {
        prime := <-primes
        fmt.Println(prime)
        primes = Filter(primes, prime)
    }
}

Batteries included

If that’s not enough

package main

import (
    "code.google.com/p/go.net/websockets"
    "github.com/surma/stacksignal"
    "github.com/voxelbrain/goptions"
    "labix.org/v2/mgo"
)

func main() {
    // ...
}

Dependencies will be automatically installed.

Documentation

Go 1.1

This is from November!

Go 1.1 – Toolchain

Go 1.1 – Library

Further reading

All about Go:

Andrew Gerrand’s Chat Roulette talk

"Go Concurrency Patterns" by Rob Pike:

Further visiting

GDG Berlin Golang

Tomorrow 7pm @c-base: Go IDEs/Editors and a webservice in Go

Thank you

Alexander Surma

Voxelbrain, GDG Berlin Golang