The Go Programming Language
Russ Cox
CNS Winter Research Review
January 21, 2010
 
	
Go
	New
	Experimental
	Concurrent
	Garbage-collected
	Systems
	Language
	Hello, world
package main
import "fmt"
func main() {
	fmt.Printf("Hello, 世界\n")
}
 
	
History
	Design started in late 2007.
	Implementation starting to work mid-2008.
	Released as an open source project in November 2009.
	Work continues.
	Robert Griesemer, Ken Thompson, Rob Pike, Ian Lance Taylor, Russ Cox, many others
	
Goals and Motivation
	Go fast!
	Make programming fun again.
	Targeted at systems software, broadly.
	Why isn't programming fun?
	
	Compiled, statically-typed languages (C, C++, Java) require too much typing and too much typing:
	
		- verbose, lots of repetition
 
		- too much focus on type hierarchy
 
		- types get in the way as much as they help
 
		- compiles take far too long
 
	
	 
	
	Dynamic languages (Python, JavaScript) fix these problems (no more types, no more compiler) but introduce others:
	
		- errors at run time that should be caught statically
 
		- no compilation means slow code
 
	
	 
	Can we combine the best of both?
 
	Why a new language?
	
	
No new systems language in 10+ years.
	Current languages designed before ...
	... rise of large-scale, networked and multicore computing
	... rise of Internet-scale distributed development (many libraries)
	
 
	
Go
	Make the language fast.
	Make the tools fast.
	
Compilation Demo
	Build all standard Go packages: ~120,000 lines of code.
	
Go in one slide
	Lightweight syntax.
	Static types: enough to compile well, but inferred much of the time.
	Methods: on any type, orthogonal to type system.
	Abstract types: interface values, relations inferred statically.
	Visibility: inferred from case of name.
	First-class functions.
	Garbage collection.
	
	Lightweight feel of a scripting language but compiled.
	Go, concurrently
	Cheap to create a new flow of control (goroutine):
func main() {
	go expensiveComputation(x, y, z)
	anotherExpensiveComputation(a, b, c)
}
	Two expensive computations in parallel.
 
	Go, concurrently
	Cheap to create a new flow of control (goroutine):
	for {
		rw := l.Accept()
		conn := newConn(rw, handler)
		go conn.serve()
	}
	Concurrent web server.
	Network connections multiplexed onto epoll.
		
		- many blocked Read calls != many blocked OS threads
 
		
 
	Go, synchronized
	Use explicit messages to communicate and synchronize.
func computeAndSend(ch chan int, x, y, z int) {
	ch <- expensiveComputation(x, y, z)
}
func main() {
	ch := make(chan int)
	go computeAndSend(ch, x, y, z)
	v2 := anotherExpensiveComputation(a, b, c)
	v1 := <-ch
	fmt.Println(v1, v2)
}
	Notice communication of result in addition to synchronization.
 
	Go, synchronized
	RPC client
func (client *Client) Call(method string, args, reply interface{}) os.Error {
    // Send RPC message.
    call := client.Go(method, args, reply, nil)
    // Read reply from Done channel.
    <-call.Done
    return call.Error
}
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
Read response from network.
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
Look up request by sequence number.
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
Decode response fields from payload.
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
Tell client that it finished.
 
	Go, synchronized
	RPC client demux
func (client *Client) input() {
	for {
		resp := client.readResponse()
		client.mutex.Lock()
		c := client.pending[resp.Seq]
		client.pending[resp.Seq] = c, false
		client.mutex.Unlock()
		if resp.Error != "" {
			c.Error = os.ErrorString(resp.error)
		}
		resp.Decode(c.Reply)
		c.Done <- c
	}
}
Can create multiple Calls with same Done channel
and distinguish which finished by inspecting value sent on channel.
 
	
Goroutine demo
	Chain together 100,000 goroutines connected by 100,001 channels.
	Send a value to one end of the chain.
	Each passes it along, increments.
	Receive value out the other end of the chain.
	
Go Status
	Go Status
	Open source:
	
		- released on November 10, 2009
 
		- regular releases (~ weekly)
 
		- all development done in public Mercurial repository
 
		- outside contributions welcome
 
		- two independent compiler implementations
 
		- XML, JSON, HTTP, TLS/SSL, native RPC, (network channels,) ...
 
	
 
	Go Status
	Open source
	Portable:
	
		- FreeBSD, Linux, OS X (x86, x86-64)
 
		- (in progress) Linux arm, Native Client x86, Windows x86.
 
	
 
	Go Status
	Open source
	Portable
	Still in progress, experimental.  Yet to come:
	
		- production garbage collector
 
		- generics?
 
		- exceptions?
 
		- unions or sum types?
 
	
 
	Questions?