blob: 07420250dbcb5a9961998cf8c2d7986132de5ac8 [file] [log] [blame]
Go for C++ developers
Francesc Campoy
Developer, Advocate, and Gopher at Google
* Go for C++ developers
- let's talk about Go
- how do I do X in Go?
- concurrency, because it's awesome
- Q & A: but feel free to interrupt anytime
- We might not go through all the slides
* About me
*2011* Joined Google as a Software Engineer
- writing mostly in C++ and Python
- used to think _smart_code_ was better than boring code
*2012* Joined the Go team as a Developer Programs Engineer
*2014*to*today* Developer Advocate for the Google Cloud Platform
* Let's talk about Go
* Go is
Go is
- open source
- statically typed
- object oriented (if you ask me)
- compiled
- memory safe
- type safe
* Why Go?
Go was created for:
- scalability
- concurrency
- simplicity
* Who uses Go?
- YouTube
- Docker
- SoundCloud
- Canonical
- CloudFlare
- Mozilla
- ...
* Who uses Go?
.image go4cpp/trends.png _ 800
.caption Google Trends for [[][golang]]
* Some Go features
* Go types
- primitive types
int, uint, int8, uint8, ...
bool, string
float32, float64
complex64, complex128
- structs
struct {
Name string
Age int
- slices and arrays
[]int, [3]string, []struct{ Name string }
- maps
* Kinds of types (continued)
- pointers
*int, *Person
- functions
func(int, int) int
- channels
chan bool
- interfaces
interface {
* Type declarations
type [name] [specification]
`Person` is a `struct` type.
type Person struct {
name string
age int
`Celsius` is a `float64` type.
type Celsius float64
* Function declarations
func [name] ([params]) [return value]
func [name] ([params]) ([return values])
A sum function:
func sum(a int, b int) int {
return a + b
A function with multiple return values:
func divMod(a, b int) (int, int) {
return a / b, a % b
Made clearer by naming the return values:
func divMod(den, div int) (quo, rem int) {
return den / div, den % div
* Method declarations
func ([receiver]) [name] ([params]) ([return values])
A method on a struct:
func (p Person) IsMinor() bool {
return p.age < 18
But also a method on a `float64`:
func (c Celsius) Freezing() bool {
return c <= 0
_Constraint:_ Methods can be defined *only* on types declared in the same package.
// This won't compile
func (s string) Length() int { return len(s) }
* Declaring variables
Normal declaration:
var text string = "hello"
You can omit types:
var text = "hello"
And inside of functions:
text := "hello"
Other types
a := 0 // int
b := true // boolean
f := 1.0 // float64
p := Person{"Francesc", "Campoy"} // Person
* No implicit numeric conversion
Given types:
type Celsius float64
type Fahrenheit float64
And the variables:
var freezing Fahrenheit = 32
var boiling Celsius = 100
This code won't compile:
sauna := (freezing + boiling) / 2
There's no implicit numeric conversion in Go.
* Pointers and memory allocation
* Pointers
Go has pointers:
var p *int
p = new(int)
But no pointer arithmetics:
var p *int = &a[0]
var q = p+2 // invalid
There's `new` but there's no `delete`.
Memory is garbaged collected after it's no longer accessible.
* Memory allocation
The compiler decides where to allocate based on escape analysis.
Using `new` doesn't imply using the heap:
func get() int {
n := new(int)
return *n
And not all values in the heap are created with `new`:
func get() *int {
n := 4
return &n
* Choosing what allocation you want
You can *not* decide where a value is allocated.
But you can see what kind of allocation is used:
$ go tool 6g -m stack.go
stack.go:3: can inline get
stack.go:4: get new(int) does not escape
Compare to:
$ go tool 6g -m heap.go
heap.go:3: can inline get
heap.go:4: moved to heap: n
heap.go:5: &n escapes to heap
- encapsulation of acquisition and disposition of resources
- exception safe
An example:
void write_to_file (const std::string & message) {
// mutex to protect file access
static std::mutex mutex;
// lock mutex before accessing file
// at the end of the scope unlock mutex
std::lock_guard<std::mutex> lock(mutex);
// mutual exclusion access section
* RAII in Go: defer
The `defer` statement:
- schedules a function call at the end of the current function
- stacks all deferred calls - first in first out
var m sync.Mutex
func writeToFile(msg string) error {
defer m.Unlock()
// mutual exclusion access section
* Garbage collection
Go is a garbage collected language
But it's easy to limit heap allocations
- many values are allocated on the stack
- object pools: [[sync.Pool][]]
- contiguous area of memory
.play go4cpp/sizes.go /type/,
* More about garbage collection
Trusted in production.
Brad Fitzpatrick's talk on migrating from C++ to Go:
- [[][ Powered by Go]]
Current state and road plan:
- [[][]]
* Inheritance vs Composition
* Inheritance vs Composition
- Inheritance breaks encapsulation
- Composition causes boilerplate to proxy all methods
type Engine struct{}
func (e Engine) Start() { ... }
func (e Engine) Stop() { ... }
We want `Car` to be able to `Start` and `Stop` too.
More detail in my talk [[][Go for Javaneros]]
* Struct embedding
Composition + Proxy of selectors
.play go4cpp/embedding.go /type/,
* Struct embedding and the diamond problem
What if two embedded fields have the same type?
.play go4cpp/diamond.go /type/,
* Struct embedding
It looks like inheritance but _it_is_not_inheritance_.
It is composition.
Used to share implementations between different types.
What if want to share behavior instead?
* Interfaces
* Interfaces
An interface is a set of methods.
In Java (C++ doesn't have interfaces)
interface Switch {
void open();
void close();
In Go:
type OpenCloser interface {
* It's all about satisfaction
Java interfaces are satisfied *explicitly*.
C++ abstract classes need to be extended *explicitly*
Go interfaces are satisfied *implicitly*.
.image // _ 512
.caption Picture by Gorupdebesanez [[][CC-BY-SA-3.0]], via [[][Wikimedia Commons]]
* Go: implicit satisfaction
- fewer dependencies
- no type hierarchy
- organic composition
* Structural subtyping
Better than duck typing. Verified at compile time.
.image go4cpp/duck.jpg 500 500
* FuncDraw: an example on interfaces
.image go4cpp/funcdraw.png 500 700
* FuncDraw: package parser
Package `parse` provides a parser of strings into functions.
func Parse(text string) (*Func, error) { ... }
`Func` is a struct type, with an `Eval` method.
type Func struct { ... }
func (p *Func) Eval(x float64) float64 { ... }
* FuncDraw: package draw
Package draw generates images given a function.
func Draw(f *parser.Func) image.Image {
for x := start; x < end; x += inc {
y := f.Eval(x)
`draw` depends on `parser`, which makes testing hard.
* Breaking dependencies
Let's use an interface instead
type Evaluable interface {
Eval(float64) float64
func Draw(f Evaluable) image.Image image.Image {
for x := start; x < end; x += inc {
y := f.Eval(x)
* Advanced interfaces and composition
* Struct embedding of interfaces
Embedding an interface:
- more types can be used
- limits what is added to the embedding type
type Person struct {
First string
Last string
Age int
`Employee` exposes the `Age` of `Person`
type Employee struct {
e := Employee{Person{"John", "Doe", 49}}
* Choosing what to proxy
But we could hide it by choosing an interface:
type Employee struct {
type Namer interface {
Name() string
And we need to make `Person` satisfy `Namer`
func (e Person) Name() string { return e.First + e.Last }
And the rest of the code still works:
e := Employee{Person{"John", "Doe", 49}}
* Easy mocking of interfaces
Given this function:
.code go4cpp/mock.go /func/,/^}/
How would you test it?
* Easy mocking of interfaces
`net.Conn` is an interface defined in the `net` package of the standard library.
type Conn interface {
Read(b []byte) (n int, err error)
Write(b []byte) (n int, err error)
Close() error
LocalAddr() Addr
RemoteAddr() Addr
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
We need a fake `net.Conn`!
* One solution
We could define a new type that satisfies `net.Conn`
type fakeConn struct {}
func (c fakeConn) Read(b []byte) (n int, err error) {...}
func (c fakeConn) Write(b []byte) (n int, err error) {...}
func (c fakeConn) Close() error {...}
But, is there a better way?
* The better way
.code go4cpp/mock.go /type fakeConn/,/end_fake/
And our test can look like:
.play go4cpp/mock.go /func main/,
* Concurrency
* Concurrency
It is part of the language, not a library.
Based on three concepts:
- goroutines: lightweight threads
- channels: typed pipes used to communicate and synchronize between goroutines
- select: control structure to coordinate concurrent operations
.image go4cpp/funnelin.jpg 300 700
* Sleep and talk
.code go4cpp/conc1.go /sleepAndTalk/,/^}/
We want a message per second.
.play go4cpp/conc1.go /func main/,/^}/
What if we started all the `sleepAndTalk` concurrently?
Just add `go`!
* Concurrent sleep and talk
.play go4cpp/conc2.go /func main/,/^}/
That was fast ...
When the `main` goroutine ends, the program ends.
* Concurrent sleep and talk with more sleeping
.play go4cpp/conc3.go /func main/,/^}/
But synchronizing with `Sleep` is a bad idea.
* Communicating through channels
`sleepAndTalk` sends the string into the channel instead of printing it.
.code go4cpp/chan.go /sleepAndTalk/,/^}/
We create the channel and pass it to `sleepAndTalk`, then wait for the values to be sent.
.play go4cpp/chan.go /func main/,/^}/
* Aside: a web server
A production ready web server.
.play go4cpp/webserver.go
* Let's count on the web
Why is this wrong?
.play go4cpp/badcounter.go /nextID/,
* Let's count on the web correctly
We receive the next id from a channel.
.code go4cpp/goodcounter.go /nextID/,/^}/
We need to send ids into the channel.
.code go4cpp/goodcounter.go /counter/,/^}/
* Let's count on the web correctly
And we need to do both at the same time.
.play go4cpp/goodcounter.go /func main/,/^}/
* Let's fight!
`select` allows us to choose among multiple channel operations.
.play go4cpp/battle.go /battle/,/^}/
Go - [[http://localhost:8080/fight?usr=go]]
C++ - [[http://localhost:8080/fight?usr=cpp]]
* Chain of gophers
.image go4cpp/chain.jpg
Ok, I'm just bragging here
* Chain of gophers
.play go4cpp/goroutines.go /func f/,
* Concurrency is very powerful
And there's lots to learn!
- [[][Go Concurrency Patterns]], by Rob Pike
- [[][Advanced Concurrency Patterns]], by Sameer Ajmani
- [[][Concurrency is not Parellelism]], by Rob Pike
.image go4cpp/busy.jpg
* In conclusion
- Go is simple, consistent, readable, and fun.
- All types are equal: methods on any type.
- Implicit satisfaction of interfaces makes code easier to reuse.
- Use composition instead of inheritance.
- Struct embedding is a powerful tool.
- Concurrency is awesome, and you should check it out.
* What to do next?
Learn Go on your browser with [[][]]
Find more about Go on [[][]]
Join the community at [[!forum/Golang-nuts][golang-nuts]]
Link to the slides [[]]