The Go Programming Language
Russ Cox
Stanford University
January 12, 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
Why?
Go fast!
Make programming fun again.
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?
Go
Make the language fast.
Make the tools fast.
Go Approach: Static Types
Static types, but declarations can infer type from expression:
var one, hi = 1, "hello"
var double = func(x int) int { return x*2 }
Not full Hindley-Milner type inference.
Go Approach: Methods
Methods can be defined on any type.
type Point struct {
X, Y float64
}
func (p Point) Abs() float64 {
return math.Sqrt(p.X*p.X + p.Y*p.Y)
}
Go Approach: Methods
Methods can be defined on any type.
type MyFloat float64
func (f MyFloat) Abs() float64 {
v := float64(f)
if v < 0 {
v = -v
}
return v
}
Go Approach: Abstract Types
An interface type lists a set of methods. Any value with those methods satisfies the interface.
type Abser interface {
Abs() float64
}
func AbsPrinter(a Abser)
Can use Point or MyFloat (or ...):
p := Point{3, 4}
AbsPrinter(p)
f := MyFloat(-10)
AbsPrinter(f)
Notice that Point never declared that it implements Abser. It just does. Same with MyFloat.
Go Approach: Packages
A Go program comprises one or more packages.
Each package is one or more source files compiled and imported as a unit.
package draw
type Point struct {
X, Y int
}
package main
import "draw"
var p draw.Point
Go Approach: Visibility
Inside a package, all locally defined names are visible in all source files.
When imported, only the upper case names are visible.
package draw
type Point struct {
X, Y int
dist float64
}
type cache map[Point] float64
Clients that import "draw"
can use the black names only.
“Shift is the new public
.”
Go Approach: Concurrency
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 Approach: Synchronization
Use explicit messages to communicate and synchronize.
func computeAndSend(c chan int, x, y, z int) {
c <- expensiveComputation(x, y, z)
}
func main() {
c := make(chan int)
go computeAndSend(c, x, y, z)
v2 := anotherExpensiveComputation(a, b, c)
v1 := <-c
fmt.Println(v1, v2)
}
Notice communication of result in addition to synchronization.
Go Fast: Language
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.
Concurrency: lightweight way to start new thread of control.
Synchronization: explicit, easy message passing.
Lightweight feel of a scripting language but compiled.
Compile fast
Observation: much of the compile time for a source file is spent processing
other, often unrelated files.
In C: a.c
includes b.h
, which includes c.h
, which includes d.h
.
Except that it's more often a tree instead of a chain.
On my Mac (OS X 10.5.8, gcc 4.0.1):
- C:
#include <stdio.h>
reads 360 lines from 9 files.
- C++:
#include <iostream>
reads 25,326 lines from 131 files.
- Objective C:
#include <Carbon/Carbon.h>
reads 124,730 lines from 689 files.
And we haven't done any real work yet!
Same story in Java, Python, but reading binaries instead of source files.
Implementation: Summarize Dependencies
package gui
import "draw"
type Mouse struct {
Loc draw.Point
Buttons uint
}
Compiled form of gui
summarizes the necessary part of draw
(just Point
).
Implementation: Summarize Dependencies
Compiled form of gui
summarizes the necessary part of draw
(just Point
). Pseudo-object:
package gui
type draw.Point struct {
X, Y int
}
type gui.Mouse struct {
Loc draw.Point
Buttons uint
}
A file that imports gui
compiles without consulting draw
or its dependencies.
In Go: import "fmt"
reads one file: 184 lines summarizing types from 7 packages.
Tiny effect in this program but can be exponential in large programs.
Compilation Demo
Build all standard Go packages: ~120,000 lines of code.
Go Status
Open source:
- released on November 10, 2009
- regular releases (~ weekly)
- all development done in public Mercurial repository
- outside contributions welcome
Portable:
- FreeBSD, Linux, OS X (x86, x86-64)
- (in progress) Linux arm, Native Client x86, Windows x86.
Still in progress, experimental. Yet to come:
- mature garbage collector
- generics?
- exceptions?
- unions or sum types?
Questions?