Hello, Gophers! Gophercon Opening Keynote 24 April 2014 Rob Pike Google, Inc.

Video A video of this talk was recorded at GopherCon in Denver. Watch the talk on YouTube 2

Hello, gophers! 3

Hello, gophers! package main import "fmt" func main() { fmt.Printf("Hello, gophers!

") } 4

History This is a historic occasion. Go has achieved a level of success worthy of a conference. 5

Success Many factors contribute to that success. features

lack of features

combination of features

design

people

time 6

Case study A look back, focusing on code. 7

Two programs A close look at two programs. First is the first Go program you ever saw. Historic for you.

Second is the first Go program we ever saw. Historic for all gophers. First up: "hello, world". 8

hello.b main( ) { extrn a, b, c; putchar(a); putchar(b); putchar(c); putchar('!*n'); } a 'hell'; b 'o, w'; c 'orld'; First appeared in a 1972 B tutorial by Brian W. Kernighan.

(Not, as sometimes claimed, a few years earlier in BCPL.) 9

hello.c main() { printf("hello, world"); } First appeared in

Programming in C: A Tutorial, by Brian W. Kernighan, 1974.

Came as a document with Unix v5. 10

hello.c main() { printf("hello, world

"); } First appeared in

The C Programming Language, by Brian W. Kernighan and Dennis M. Ritchie, 1978. 11

hello.c, Draft ANSI C #include <stdio.h> main() { printf("hello, world

"); } Appeared in

The C Programming Language, Second Edition, (Based on Draft-Proposed ANSI C)

by Brian W. Kernighan and Dennis M. Ritchie, 1988. 12

hello.c, ANSI C89 #include <stdio.h> main(void) { printf("hello, world

"); } Appeared in

The C Programming Language, Second Edition, round two,

by Brian W. Kernighan and Dennis M. Ritchie, 1988. "You've gotta put a void THERE?" -Ken Thompson 13

A generation or two later... (Skipping all the intermediate languages.) Go discussions start in late 2007. Specification first drafted in March 2008.

For experimentation and prototyping, compiler work already underway.

Initially generated C output.

Once the specification arose, compiler rewritten to generate native code. 14

hello.go, June 6, 2008 package main func main() int { print "hello, world

"; return 0; } First checked-in test.

The print builtin is all we have, and main returns an int .

Note: no parentheses on print . 15

hello.go, June 27, 2008 package main func main() { print "hello, world

"; } When main returns, the program calls exit(0) . 16

hello.go, August 11, 2008 package main func main() { print("hello, world

"); } Parentheses now required: print now a function not a primitive. 17

hello.go, October 24, 2008 package main import "fmt" func main() { fmt.printf("hello, world

"); } The "printf as we know and love it" goes in.

(The test still uses print not printf ; we've switched examples here.) 18

hello.go, January 15, 2009 package main import "fmt" func main() { fmt.Printf("hello, world

"); } Upper case for export. "Casification." 19

hello.go, Dec 11, 2009 package main import "fmt" func main() { fmt.Printf("hello, world

") } No more semicolons.

A major change that occurs after the open source release (Nov 10, 2009). The current version. It took us a while to get here (32 years!). A lot of history. 20

Not just C We "started with C" but Go is profoundly different.

Some of the languages that influenced and informed the design of Go: C: statement and expression syntax

Pascal: declaration syntax

Modula 2, Oberon 2: packages

CSP, Occam, Newsqueak, Limbo, Alef: concurrency

BCPL: the semicolon rule

Smalltalk: methods

Newsqueak: <- , :=

APL: iota And others. Also some was invented whole: defer , constants, for instance. Plus lessons good and bad from all those plus:

C++, C#, Java, JavaScript, LISP, Python, Scala, ... 21

hello.go, Go version 1 Which brings us to today. package main import "fmt" func main() { fmt.Println("Hello, Gophers (some of whom know 日本語)!") } Let's dig deeper, break this down. 22

Hello, world in 16 tokens package

main

import

"fmt"

func

main

(

)

{

fmt

.

Println

(

"Hello, Gophers (some of whom know 日本語)!"

)

} 23

package Major topic in early design discussions: Key to scalability. What is a package? Ideas from Modula-2 etc.

Why are there packages?

Hold all the information you need to build.

No circular dependencies (imports).

No subpackages.

Separation of package name and package path.

Visibility is package-level, not type-level.

Within a package, you have the whole language, outside only what you permit. 24

main One place where C legacy shows through.

Was originally Main for some forgotten reason.

Main package, main function.

Special because the root of the initialization tree. 25

import Mechanism for loading a package.

Implemented by the compiler (as opposed to a text processor).

Worked hard to make it efficient and linear.

Imports a package, not a set of identifiers. As for export: It used to be a keyword. 26

"fmt" Package path is just a string, not a list of identifiers.

Allows the language to avoid defining what it means—adaptability.

From the beginning wanted a URL as an option.

Allows for future growth. 27

func A keyword introduces functions (and types, variables, constants) for easy parsing.

Easy parsing is important with function literals (closures). By the way, keyword was originally function . 28

Aside: Mail thread from February 6, 2008 From: Ken Thompson <ken@google.com>

To: gri, r larry and sergey came by tonight. we

talked about go for more than an hour.

they both said they liked it very much. p.s. one of larrys comments was "why isnt function spelled func?" --- From: Rob Pike <r@google.com>

To: ken, gri fine with me. seems compatible with 'var'. anyway we can always say, "larry said to call it 'func'" 29

main Where program starts... except it isn't.

Separation of initialization from normal execution, long planned.

Where does initialization happen?

Feeds back to package design. 30

() Look Ma, no void .

No return value for main : handled by runtime.

No function args (command line is in os package).

No return value. Return values and syntax. 31

{ Braces not spaces.

And not square brackets.

Why is the newline after the brace? 32

fmt All imported identifiers are qualified by their import.

Every identifier is either local to package or func, or qualified by type or import.

Profound effect on readability. Why fmt not format ? 33

. How many uses are there in Go for a period token? (Lots.)

The meaning of a.B requires using the type system.

But it is clear to humans and very easy to read. Autopromotion of pointers (no -> operator). 34

Println Println not println : capitals for export.

Always knew it would be reflection-driven. (Safety, formatless printing.)

Variadic functions.

Argument type was (...) ; became (...interface{}) on Feb 1, 2010. 35

( Traditional function syntax. 36

"Hello, Gophers (some of whom know 日本語)!" UTF-8 input source, so strings as literals are UTF-8 automatically.

But what is a string?

One of the first things written in the specification, hardly changed today. blog.golang.org/strings 37

) No semicolon.

Semicolons went away shortly after release.

Much futzing around to try to cull them in early days.

Eventually accepted the BCPL approach. 38

} Done. 39

Aside: Not discussed types

constants

methods

interfaces

libraries

memory management

concurrency (coming up) Plus tools, ecosystem, community, ...:

Language is central but only part of the story. 40

Success Factors: building on history

building on experience

process of design

early ideas refined into final approach

concentrated effort by a small dedicated team Finally: Commitment. Go 1.0 locked down the language and libraries. 41

Another round Now watch similar evolution of a second program. 42

Problem: Prime sieve Problem specification from

Communicating Sequential Processes, by C. A. R. Hoare, 1978 "Problem: To print in ascending order all primes less than

10000. Use an array of processes, SIEVE, in which each

process inputs a prime from its predecessor and prints it.

The process then inputs an ascending stream of numbers

from its predecessor and passes them on to its successor,

suppressing any that are multiples of the original prime. " 43

Solution Defined in the 1978 CSP paper.

(Note: not the sieve of Eratosthenes.) "This beautiful solution was contributed by David Gries." 44

CSP In Hoare's 1978 CSP paper [SIEVE(i:1..100):: p,mp:integer; SIEVE(i - 1)?p; print!p; mp := p; comment mp is a multiple of p; *[m:integer; SIEVE(i - 1)?m → *[m > mp → mp := mp + p]; [m = mp → skip ||m < mp → SIEVE(i + 1)!m ] ] ||SIEVE(0)::print!2; n:integer; n := 3; *[n < 10000 → SIEVE(1)!n; n := n + 2] ||SIEVE(101)::*[n:integer;SIEVE(100)?n → print!n] ||print::*[(i:0..101) n:integer; SIEVE(i)?n → ...] ] No channels, just processes so number of primes is fixed by program. 45

Newsqueak circa 1988.

Language by Rob Pike, program by Tom Cargill via Doug McIlroy. Uses channels, so length of run is programmable.

(Where did the idea of channels come from?) counter:=prog(end: int, c: chan of int) { i:int; for(i=2; i<end; i++) c<-=i; }; filter:=prog(prime: int, listen: chan of int, send: chan of int) { i:int; for(;;) if((i=<-listen)%prime) send<-=i; }; 46

Newsqueak (cont'd) sieve:=prog(c: chan of int) { for(;;){ prime:=<-c; print(prime, " "); newc:=mk(chan of int); begin filter(prime, c, newc); c=newc; } }; count:=mk(chan of int); begin counter(10000, count); begin sieve(count); ""; 47

sieve.go, March 5, 2008 First version in a Go specification, probably the second non-trivial program written.

> to send, < to receive. Channels are pointers. Main is capitalized. package Main // Send the sequence 2, 3, 4, ... to channel 'ch'. func Generate(ch *chan> int) { for i := 2; ; i++ { >ch = i; // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func Filter(in *chan< int, out *chan> int, prime int) { for ; ; { i := <in; // Receive value of new variable 'i' from 'in'. if i % prime != 0 { >out = i; // Send 'i' to channel 'out'. } } } 48

sieve.go, March 5, 2008 (cont'd) // The prime sieve: Daisy-chain Filter processes together. func Sieve() { ch := new(chan int); // Create a new channel. go Generate(ch); // Start Generate() as a subprocess. for ; ; { prime := <ch; printf("%d

", prime); ch1 := new(chan int); go Filter(ch, ch1, prime); ch = ch1; } } func Main() { Sieve(); } 49

sieve.go, July 22, 2008 -< to send, <- to receive. Channels still pointers. Now main not capitalized. package main // Send the sequence 2, 3, 4, ... to channel 'ch'. func Generate(ch *chan-< int) { for i := 2; ; i++ { ch -< i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func Filter(in *chan<- int, out *chan-< int, prime int) { for { i := <-in; // Receive value of new variable 'i' from 'in'. if i % prime != 0 { out -< i // Send 'i' to channel 'out'. } } } 50

sieve.go, July 22, 2008 (cont'd) // The prime sieve: Daisy-chain Filter processes together. func Sieve() { ch := new(chan int); // Create a new channel. go Generate(ch); // Start Generate() as a subprocess. for { prime := <-ch; printf("%d

", prime); ch1 := new(chan int); go Filter(ch, ch1, prime); ch = ch1 } } func main() { Sieve() } 51

sieve.go, September 17, 2008 Communication operators now prefix and postfix <- . Channels still pointers. package main // Send the sequence 2, 3, 4, ... to channel 'ch'. func Generate(ch *chan <- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func Filter(in *chan <- int, out *<-chan int, prime int) { for { i := <-in; // Receive value of new variable 'i' from 'in'. if i % prime != 0 { out <- i // Send 'i' to channel 'out'. } } } 52

sieve.go, September 17, 2008 (cont'd) // The prime sieve: Daisy-chain Filter processes together. func Sieve() { ch := new(chan int); // Create a new channel. go Generate(ch); // Start Generate() as a subprocess. for { prime := <-ch; print(prime, "

"); ch1 := new(chan int); go Filter(ch, ch1, prime); ch = ch1 } } func main() { Sieve() } 53

sieve.go, January 6, 2009 The make builtin arrives. No pointers. Code wrong! (One * left, bad argument types.) package main // Send the sequence 2, 3, 4, ... to channel 'ch'. func Generate(ch chan <- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func Filter(in chan <- int, out *<-chan int, prime int) { for { i := <-in; // Receive value of new variable 'i' from 'in'. if i % prime != 0 { out <- i // Send 'i' to channel 'out'. } } } 54

sieve.go, January 6, 2009 (cont'd) // The prime sieve: Daisy-chain Filter processes together. func Sieve() { ch := make(chan int); // Create a new channel. go Generate(ch); // Start Generate() as a subprocess. for { prime := <-ch; print(prime, "

"); ch1 := make(chan int); go Filter(ch, ch1, prime); ch = ch1 } } func main() { Sieve() } 55

sieve.go, September 25, 2009 First correct modern version. Also: capitalization gone. Uses fmt . package main import "fmt" // Send the sequence 2, 3, 4, ... to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i; // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i; // Send 'i' to channel 'dst'. } } } // The prime sieve: Daisy-chain filter processes together. func sieve() { ch := make(chan int); // Create a new channel. go generate(ch); // Start generate() as a subprocess. for { prime := <-ch; fmt.Print(prime, "

"); ch1 := make(chan int); go filter(ch, ch1, prime); ch = ch1; } } func main() { sieve(); } 56

sieve.go, September 25, 2009 (cont'd) // +build ignore,OMIT package main import "fmt" // Send the sequence 2, 3, 4, ... to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i; // Send 'i' to channel 'ch'. } } // Copy the values from channel 'in' to channel 'out', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i; // Send 'i' to channel 'dst'. } } } // The prime sieve: Daisy-chain filter processes together. func sieve() { ch := make(chan int); // Create a new channel. go generate(ch); // Start generate() as a subprocess. for { prime := <-ch; fmt.Print(prime, "

"); ch1 := make(chan int); go filter(ch, ch1, prime); ch = ch1; } } func main() { sieve(); } 57

sieve.go, December 10, 2009 Semicolons gone. Program as it is today. package main import "fmt" // Send the sequence 2, 3, 4, … to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'src' to channel 'dst', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i // Send 'i' to channel 'dst'. } } } // The prime sieve: Daisy-chain filter processes together. func sieve() { ch := make(chan int) // Create a new channel. go generate(ch) // Start generate() as a subprocess. for { prime := <-ch fmt.Print(prime, "

") ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1 } } func main() { sieve() } 58

sieve.go, December 10, 2009 (cont'd) // +build ignore,OMIT package main import "fmt" // Send the sequence 2, 3, 4, … to channel 'ch'. func generate(ch chan<- int) { for i := 2; ; i++ { ch <- i // Send 'i' to channel 'ch'. } } // Copy the values from channel 'src' to channel 'dst', // removing those divisible by 'prime'. func filter(src <-chan int, dst chan<- int, prime int) { for i := range src { // Loop over values received from 'src'. if i%prime != 0 { dst <- i // Send 'i' to channel 'dst'. } } } // The prime sieve: Daisy-chain filter processes together. func sieve() { ch := make(chan int) // Create a new channel. go generate(ch) // Start generate() as a subprocess. for { prime := <-ch fmt.Print(prime, "

") ch1 := make(chan int) go filter(ch, ch1, prime) ch = ch1 } } func main() { sieve() } "This beautiful solution was contributed by a decades-long process of design." 59

Aside: Not discussed select The core connector for real concurrent applications. (A fact not always appreciated).

Origins in Dijkstra's guarded commands.

Made truly concurrent in Hoare's CSP.

Refined through Newsqueak, Alef, Limbo, and other routes. Go's version specified on March 26, 2008.

Simplifications, clarifications, syntactic considerations. 60

Stability Sieve program unchanged since late 2009—stability! Open source systems are not always dependably compatible and stable. Go is. This is a very important reason for Go's success. 61

Trends Graphs in usage metrics show knee in curve at Go 1.0 release. 62

Success The factors for Go's success? Obvious: Features and tools. concurrency

garbage collection

efficient implementation

static types but dynamic feel

rich but limited standard library

tooling (and the factors that make it possible)

gofmt

programming in the large 63

Success Less obvious: process. focus on the original goals

concentrated development followed by freeze

consensus of a small core team

vital contributions from a community that "gets it"

rich ecosystem generated as a consequence In short, an open source community that shares our mission,

coupled to a language designed for today's world. 64

Fitness to purpose From Go: the emerging language of cloud infrastructure by Donnie Berkholz, March 2014.

golang.org/s/emerging 65

The future This is where you come in! 66