|
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 |
|
- ... |
|
|
|
[[/wiki/GoUsers][go.dev/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! |
|
|
|
- [[/talks/2012/concurrency.slide#1][Go Concurrency Patterns]], by Rob Pike |
|
- [[/talks/2013/advconc.slide#1][Advanced Concurrency Patterns]], by Sameer Ajmani |
|
- [[/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 [[/tour/][go.dev/tour]] |
|
|
|
Find more about Go on [[/][go.dev]] |
|
|
|
Join the community at [[https://groups.google.com/forum/#!forum/Golang-nuts][golang-nuts]] |
|
|
|
Link to the slides [[/talks/2014/go4java.slide]] |