blob: 334c5b9585daf3c0f5ac15b0053b006adc0ffcce [file] [log] [blame]
Go for Javaneros (Javaïstes?)
#go4java
Francesc Campoy
Gopher and Developer Advocate
Google
@francesc
campoy@golang.org
* What is Go?
Go is an open-source programming language
- created at Google,
- to solve Google-scale problems.
.image go4java/img/gopher.jpg 450 _
* Who uses Go?
Google:
- YouTube
- dl.google.com
Others:
- dotCloud (Docker)
- SoundCloud
- Canonical
- CloudFlare
- Mozilla
- ...
[[http://golang.org/wiki/GoUsers][golang.org/wiki/GoUsers]]
* Who uses Go?
.image go4java/img/trends.png _ 800
.caption Google Trends for [[http://www.google.com/trends/explore#q=golang][golang]]
* Why Go?
* Simplicity
Minimal design
.image go4java/img/perfection.jpg
* Consistency
Orthogonal features
.image go4java/img/lego.jpg 400 _
.caption By Kenny Louie from Vancouver, Canada [[http://creativecommons.org/licenses/by/2.0][CC-BY-2.0]], via Wikimedia Commons
* Readability
The ratio of time spent reading (code) versus writing is well over 10 to 1 ... (therefore) making it easy to read makes it easier to write.”
Robert C. Martin
.image go4java/img/piet.png 500 600
* Safety
Type safety, no buffer overflows, no pointer arithmetic.
.image go4java/img/baby.jpg 500 500
* Built-in concurrency features
In a concurrent world, imperative is the wrong default!” - Tim Sweeney
Communicating Sequential Processes - Hoare (1978)
.image go4java/img/conc.jpg _ 1000
* Speed
.image go4java/img/fast.jpg 500 _
* Let's dive in
* Go and Java common aspects
Go and Java are
- object oriented
- garbage collected
- statically typed
- part of the C family
* Object oriented flavors
Go is Object Oriented, but doesn't have the keywords:
- `class`,
- `extends`, or
- `implements`.
* All types are created equal
* 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
map[string]int
* Kinds of types (continued)
- pointers
*int, *Person
- functions
func(int, int) int
- channels
chan bool
- interfaces
interface {
Start()
Stop()
}
* 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 returned values:
func div(a, b int) (int, int)
return a / b, a % b
}
Made clearer by naming the return values:
func div(den, div int) (q, rem int)
return a / b, a % b
}
* Method declarations
func ([receiver]) [name] ([params]) ([return values])
A method on a struct:
func (p Person) Major() 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) }
* Wait, pointers?
Use `&` to obtain the address of a variable.
a := "hello"
p := &a
Use `*` to dereference the pointer.
fmt.Print(*p + ", world")
No pointer arithmetic, no pointers to unsafe memory.
a := "hello"
p := &a
p += 4 // no, you can't
* Why pointers?
Control what you pass to functions.
- passing values, no side-effects:
func double(x int) {
x *= 2
}
- passing pointers: side-effects possible:
func double(x *int) {
*x *= 2
}
Control your memory layout.
- compare []Person and []*Person
* Method declarations on pointers
Receivers behave like any other argument.
Pointers allow modifying the pointed receiver:
func (p *Person) IncAge() {
p.age++
}
The method receiver is a copy of a pointer (pointing to the same address).
Method calls on nil receivers are perfectly valid (and useful!).
func (p *Person) Name() string {
if p == nil {
return "anonymous"
}
return p.name
}
* Interfaces
* Interfaces
An interface is a set of methods.
In Java:
interface Switch {
void open();
void close();
}
In Go:
type OpenCloser interface {
Open()
Close()
}
* It's all about satisfaction
Java interfaces are satisfied *explicitly*.
Go interfaces are satisfied *implicitly*.
.image //upload.wikimedia.org/wikipedia/commons/thumb/2/29/Rolling_Stones_09.jpg/512px-Rolling_Stones_09.jpg _ 512
.caption Picture by Gorupdebesanez [[http://creativecommons.org/licenses/by-sa/3.0][CC-BY-SA-3.0]], via [[http://commons.wikimedia.org/wiki/File%3ARolling_Stones_09.jpg][Wikimedia Commons]]
* Go: implicit satisfaction
_If_a_type_defines_all_the_methods_of_an_interface,_the_type_satisfies_that_interface._
Benefits:
- fewer dependencies
- no type hierarchy
- organic composition
* Structural subtyping
Think static duck typing, verified at compile time.
.image go4java/img/duck.jpg 500 500
* FuncDraw: an example on interfaces
.image go4java/img/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`
- makes testing hard
Let's use an interface instead
type Evaluable interface {
Eval(float64) float64
}
func Draw(f Evaluable) image.Image { ... }
* Inheritance vs composition
* Inheritance vs composition
Lots of articles have been written about the topic.
In general, composition is preferred to inheritance.
Lets see why.
* Runner
.code go4java/BadInheritance.java /START_RUNNER/,/END_RUNNER/
* RunCounter is-a Runner that counts
.code go4java/BadInheritance.java /START_COUNTING/,/END_COUNTING/
* Let's run and count
What will this code print?
.code go4java/BadInheritance.java /START_MAIN/,/END_MAIN/
Of course, this prints:
running one
running two
running three
my runner ran 6 tasks
Wait! How many?
* My runner ran 6 tasks? Six?
Inheritance causes:
- weak encapsulation,
- tight coupling,
- surprising bugs.
.image go4java/img/badinheritance.png
* Solution: use composition
.code go4java/Composition.java /START_COUNTING/,/BREAK_COUNTING/
* Solution: use composition (continued)
.code go4java/Composition.java /BREAK_COUNTING/,/END_COUNTING/
* Solution: use composition (continued)
*Pros*
- The bug is gone!
- `Runner` is completely independent of `RunCounter`.
- The creation of the `Runner` can be delayed until (and if) needed.
*Cons*
- We need to explicitly define the `Runner` methods on `RunCounter`:
public String getName() { return runner.getName(); }
- This can cause lots of repetition, and eventually bugs.
* There's no inheritance in Go
* There's no inheritance in Go
Let's use composition directly:
# .code go4java/runner/runner.go /type Task/,/END_TASK/
.code go4java/runner/runner.go /type Runner/,/END_RUNNER/
All very similar to the Java version.
* RunCounter
`RunCounter` has a `Runner` field.
.code go4java/runner/runner.go /type RunCounter/,
* Composition in Go
Same pros and cons as the composition version in Java.
We also have the boilerplate to proxy methods from `Runner`.
.code go4java/runner/runner.go /runner.Name/
But we can remove it!
* Struct embedding
Expressed in Go as unnamed fields in a struct.
It is still *composition*.
The fields and methods of the embedded type are defined on the embedding type.
Similar to inheritance, but the embedded type doesn't know it's embedded.
* Example of struct embedding
Given a type `Person`:
.code go4java/embedsample.go /Person/,/Hi/
We can define a type `Employee` embedding `Person`:
.code go4java/embedsample.go /Employee/,/}/
All fields and methods from `Person` are available on `Employee`:
.code go4java/embedsample.go /var/,/Introduce/
* Struct embedding
.code go4java/runner/embed.go /type RunCounter2/,
* Is struct embedding like inheritance?
No, it is better!
It is composition.
- You can't reach into another type and change the way it works.
- Method dispatching is explicit.
It is more general.
- Struct embedding of interfaces.
* Is struct embedding like inheritance?
Struct embedding is selective.
.code go4java/writecounter.go /WriteCounter/,/MAIN/
WriteCounter can be used with any `io.ReadWriter`.
.play go4java/writecounter.go /func main/,/^}/
* Easy mocking
What if we wanted to fake a part of a `net.Conn`?
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
}
I want to test `handleCon`:
.code go4java/loopback.go /handleCon/
- We could create a `fakeConn` and define all the methods of `Conn` on it.
- But that's a lot of boring code.
* Struct embedding of interfaces
_WARNING_:_Cool_stuff_
If a type T has an embedded field of a type E, all the methods of E will be defined on T.
Therefore, if E is an interface T satisfies E.
* Struct embedding of interfaces (continued)
We can test `handleCon` with the `loopBack` type.
.code go4java/loopback.go /loopBack/,/^}/
Any calls to the methods of `net.Conn` will fail, since the field is nil.
We redefine the operations we support:
.code go4java/loopback.go /Read/,
* Concurrency
* Concurrency
It is part of the language, not a library.
Based on two concepts:
- goroutines: lightweight threads
- channels: typed pipes used to communicate and synchronize between goroutines
So cheap you can use them whenever you want.
.image go4java/img/funnelin.jpg 300 700
* Sleep and talk
.code go4java/conc1.go /sleepAndTalk/,/^}/
We want a message per second.
.play go4java/conc1.go /func main/,/^}/
What if we started all the `sleepAndTalk` concurrently?
Just add `go`!
* Concurrent sleep and talk
.play go4java/conc2.go /func main/,/^}/
That was fast ...
When the `main` goroutine ends, the program ends.
* Concurrent sleep and talk with more sleeping
.play go4java/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 go4java/chan.go /sleepAndTalk/,/^}/
We create the channel and pass it to `sleepAndTalk`, then wait for the values to be sent.
.play go4java/chan.go /func main/,/^}/
* Let's count on the web
We receive the next id from a channel.
.code go4java/goodcounter.go /nextID/,/^}/
We need a goroutine sending ids into the channel.
.play go4java/goodcounter.go /func main/,/^}/
[[http://localhost:8080/next]]
* Let's fight!
`select` allows us to chose among multiple channel operations.
.play go4java/battle.go /battle/,/^}/
Go - [[http://localhost:8080/fight?usr=go]]
Java - [[http://localhost:8080/fight?usr=java]]
* Chain of gophers
.image go4java/img/chain.jpg
Ok, I'm just bragging here
* Chain of gophers
.play go4java/goroutines.go /func f/,
* Concurrency is very powerful
And there's lots to learn!
- [[http://go.dev/talks/2012/concurrency.slide#1][Go Concurrency Patterns]], by Rob Pike
- [[http://go.dev/talks/2013/advconc.slide#1][Advanced Concurrency Patterns]], by Sameer Ajmani
- [[http://go.dev/talks/2012/waza.slide#1][Concurrency is not Parallelism]], by Rob Pike
.image go4java/img/busy.jpg
* In conclusion
Go is simple, consistent, readable, and fun.
All types are equal
- methods on any type
Implicit interfaces
- Structural typing
- Less dependencies
- Code testable and reusable
Use composition instead of inheritance
- Struct embedding to remove boilerplate.
- Struct embedding of interfaces to satisfy them fast.
Concurrency is awesome, and you should check it out.
* What to do next?
Learn Go on your browser with [[http://tour.golang.org][tour.golang.org]]
Find more about Go on [[http://golang.org][golang.org]]
Join the community at [[https://groups.google.com/forum/#!forum/Golang-nuts][golang-nuts]]
Link to the slides [[http://go.dev/talks/2014/go4java.slide]]