go.talks: add "Go for Javaneros"
LGTM=adg
R=adg, jacek.masiulaniec, campoy, dan.kortschak, nightlyone, jscrockett01
CC=golang-codereviews
https://golang.org/cl/111050043
diff --git a/2014/go4java.slide b/2014/go4java.slide
new file mode 100644
index 0000000..3025c62
--- /dev/null
+++ b/2014/go4java.slide
@@ -0,0 +1,667 @@
+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 useulf!).
+
+ 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://talks.golang.org/2012/concurrency.slide#1][Go Concurrency Patterns]], by Rob Pike
+- [[http://talks.golang.org/2013/advconc.slide#1][Advanced Concurrency Patterns]], by Sameer Ajmani
+- [[http://talks.golang.org/2012/waza.slide#1][Concurrency is not Parellelism]], 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://talks.golang.org/2014/go4java.slide]]
diff --git a/2014/go4java/BadInheritance.java b/2014/go4java/BadInheritance.java
new file mode 100644
index 0000000..8388418
--- /dev/null
+++ b/2014/go4java/BadInheritance.java
@@ -0,0 +1,82 @@
+import java.util.Collection;
+import java.util.ArrayList;
+
+class BadInheritance {
+ // START_TASK OMIT
+ class Task {
+ private String message;
+
+ public Task(String message) {
+ this.message = message;
+ }
+
+ public void run() {
+ System.out.println("running " + this.message);
+ }
+ }
+ // END_TASK OMIT
+
+ // START_RUNNER OMIT
+ class Runner {
+ private String name;
+
+ public Runner(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void run(Task task) { // HL
+ task.run();
+ }
+
+ public void runAll(Task[] tasks) { // HL
+ for (Task task : tasks) {
+ run(task);
+ }
+ }
+ }
+ // END_RUNNER OMIT
+
+ // START_COUNTING OMIT
+ class RunCounter extends Runner {
+ private int count;
+
+ public RunCounter(String message) {
+ super(message);
+ this.count = 0;
+ }
+
+ @Override public void run(Task task) {
+ count++; // HL
+ super.run(task);
+ }
+
+ @Override public void runAll(Task[] tasks) {
+ count += tasks.length; // HL
+ super.runAll(tasks);
+ }
+
+ public int getCount() {
+ return count;
+ }
+ }
+ // END_COUNTING OMIT
+
+ public void test() {
+ // START_MAIN OMIT
+ RunCounter runner = new RunCounter("my runner");
+
+ Task[] tasks = { new Task("one"), new Task("two"), new Task("three")};
+ runner.runAll(tasks);
+
+ System.out.printf("%s ran %d tasks\n", runner.getName(), runner.getCount());
+ // END_MAIN OMIT
+ }
+
+ public static void main(String[] args) {
+ new BadInheritance().test();
+ }
+}
\ No newline at end of file
diff --git a/2014/go4java/Composition.java b/2014/go4java/Composition.java
new file mode 100644
index 0000000..345450a
--- /dev/null
+++ b/2014/go4java/Composition.java
@@ -0,0 +1,86 @@
+import java.util.Collection;
+import java.util.ArrayList;
+
+class Composition {
+ class Task {
+ private String message;
+
+ public Task(String message) {
+ this.message = message;
+ }
+
+ public void run() {
+ System.out.println("running " + this.message);
+ }
+ }
+
+ class Runner {
+ private String name;
+
+ public Runner(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void run(Task task) {
+ task.run();
+ }
+
+ public void runAll(Task[] tasks) {
+ for (Task task : tasks) {
+ run(task);
+ }
+ }
+ }
+
+ // START_COUNTING OMIT
+ class RunCounter {
+ private Runner runner; // HL
+ private int count;
+
+ public RunCounter(String message) {
+ this.runner = new Runner(message);
+ this.count = 0;
+ }
+
+ public void run(Task task) {
+ count++;
+ runner.run(task);
+ }
+
+ public void runAll(Task[] tasks) {
+ count += tasks.length;
+ runner.runAll(tasks);
+ }
+
+ // continued on next slide ...
+
+ // BREAK_COUNTING OMIT
+ public int getCount() {
+ return count;
+ }
+
+ public String getName() {
+ return runner.getName();
+ }
+ }
+ // END_COUNTING OMIT
+
+ public void test() {
+ // START_MAIN OMIT
+ RunCounter runner = new RunCounter("my runner");
+
+ Task[] tasks = { new Task("one"), new Task("two"), new Task("three")};
+ runner.runAll(tasks);
+
+ System.out.printf("%s ran %d tasks\n", runner.getName(), runner.getCount());
+ // END_MAIN OMIT
+ }
+
+ public static void main(String[] args) {
+ new Composition().test();
+ }
+}
diff --git a/2014/go4java/battle.go b/2014/go4java/battle.go
new file mode 100644
index 0000000..0036f16
--- /dev/null
+++ b/2014/go4java/battle.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+)
+
+var battle = make(chan string)
+
+func handler(w http.ResponseWriter, q *http.Request) {
+ select {
+ case battle <- q.FormValue("usr"):
+ fmt.Fprintf(w, "You won!")
+ case won := <-battle:
+ fmt.Fprintf(w, "You lost, %v is better than you", won)
+ }
+}
+
+func main() {
+ http.HandleFunc("/fight", handler)
+ http.ListenAndServe("localhost:8080", nil)
+}
diff --git a/2014/go4java/chan.go b/2014/go4java/chan.go
new file mode 100644
index 0000000..791a8ad
--- /dev/null
+++ b/2014/go4java/chan.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func sleepAndTalk(secs time.Duration, msg string, c chan string) {
+ time.Sleep(secs * time.Second)
+ c <- msg
+}
+
+func main() {
+ c := make(chan string)
+
+ go sleepAndTalk(0, "Hello", c)
+ go sleepAndTalk(1, "Gophers!", c)
+ go sleepAndTalk(2, "What's", c)
+ go sleepAndTalk(3, "up?", c)
+
+ for i := 0; i < 4; i++ {
+ fmt.Printf("%v ", <-c)
+ }
+}
diff --git a/2014/go4java/conc1.go b/2014/go4java/conc1.go
new file mode 100644
index 0000000..947ef7e
--- /dev/null
+++ b/2014/go4java/conc1.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func sleepAndTalk(t time.Duration, msg string) {
+ time.Sleep(t)
+ fmt.Printf("%v ", msg)
+}
+
+func main() {
+ sleepAndTalk(0*time.Second, "Hello")
+ sleepAndTalk(1*time.Second, "Gophers!")
+ sleepAndTalk(2*time.Second, "What's")
+ sleepAndTalk(3*time.Second, "up?")
+}
diff --git a/2014/go4java/conc2.go b/2014/go4java/conc2.go
new file mode 100644
index 0000000..407bcfc
--- /dev/null
+++ b/2014/go4java/conc2.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func sleepAndTalk(t time.Duration, msg string) {
+ time.Sleep(t)
+ fmt.Printf("%v ", msg)
+}
+
+func main() {
+ go sleepAndTalk(0*time.Second, "Hello")
+ go sleepAndTalk(1*time.Second, "Gophers!")
+ go sleepAndTalk(2*time.Second, "What's")
+ go sleepAndTalk(3*time.Second, "up?")
+}
diff --git a/2014/go4java/conc3.go b/2014/go4java/conc3.go
new file mode 100644
index 0000000..bd2c423
--- /dev/null
+++ b/2014/go4java/conc3.go
@@ -0,0 +1,19 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func sleepAndTalk(t time.Duration, msg string) {
+ time.Sleep(t)
+ fmt.Printf("%v ", msg)
+}
+
+func main() {
+ go sleepAndTalk(0*time.Second, "Hello")
+ go sleepAndTalk(1*time.Second, "Gophers!")
+ go sleepAndTalk(2*time.Second, "What's")
+ go sleepAndTalk(3*time.Second, "up?")
+ time.Sleep(4 * time.Second)
+}
diff --git a/2014/go4java/embedsample.go b/2014/go4java/embedsample.go
new file mode 100644
index 0000000..d475b18
--- /dev/null
+++ b/2014/go4java/embedsample.go
@@ -0,0 +1,20 @@
+package main
+
+import "fmt"
+
+type Person struct{ Name string }
+
+func (p Person) Introduce() { fmt.Println("Hi, I'm", p.Name) }
+
+type Employee struct {
+ Person
+ EmployeeID int
+}
+
+func ExampleEmployee() {
+ var e Employee
+ e.Name = "Peter"
+ e.EmployeeID = 1234
+
+ e.Introduce()
+}
diff --git a/2014/go4java/goodcounter.go b/2014/go4java/goodcounter.go
new file mode 100644
index 0000000..8cfca48
--- /dev/null
+++ b/2014/go4java/goodcounter.go
@@ -0,0 +1,22 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+)
+
+var nextID = make(chan int)
+
+func handler(w http.ResponseWriter, q *http.Request) {
+ fmt.Fprintf(w, "<h1>You got %v<h1>", <-nextID)
+}
+
+func main() {
+ http.HandleFunc("/next", handler)
+ go func() {
+ for i := 0; ; i++ {
+ nextID <- i
+ }
+ }()
+ http.ListenAndServe("localhost:8080", nil)
+}
diff --git a/2014/go4java/goroutines.go b/2014/go4java/goroutines.go
new file mode 100644
index 0000000..57bc8fd
--- /dev/null
+++ b/2014/go4java/goroutines.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+func f(left, right chan int) {
+ left <- 1 + <-right
+}
+
+func main() {
+ start := time.Now()
+ const n = 1000
+ leftmost := make(chan int)
+
+ right := leftmost
+ left := leftmost
+ for i := 0; i < n; i++ {
+ right = make(chan int)
+ go f(left, right)
+ left = right
+ }
+
+ go func(c chan int) { c <- 0 }(right)
+
+ fmt.Println(<-leftmost, time.Since(start))
+}
diff --git a/2014/go4java/img/baby.jpg b/2014/go4java/img/baby.jpg
new file mode 100644
index 0000000..2f32877
--- /dev/null
+++ b/2014/go4java/img/baby.jpg
Binary files differ
diff --git a/2014/go4java/img/badinheritance.png b/2014/go4java/img/badinheritance.png
new file mode 100644
index 0000000..91e4070
--- /dev/null
+++ b/2014/go4java/img/badinheritance.png
Binary files differ
diff --git a/2014/go4java/img/busy.jpg b/2014/go4java/img/busy.jpg
new file mode 100644
index 0000000..35ce9f4
--- /dev/null
+++ b/2014/go4java/img/busy.jpg
Binary files differ
diff --git a/2014/go4java/img/chain.jpg b/2014/go4java/img/chain.jpg
new file mode 100644
index 0000000..87f8571
--- /dev/null
+++ b/2014/go4java/img/chain.jpg
Binary files differ
diff --git a/2014/go4java/img/conc.jpg b/2014/go4java/img/conc.jpg
new file mode 100644
index 0000000..5813956
--- /dev/null
+++ b/2014/go4java/img/conc.jpg
Binary files differ
diff --git a/2014/go4java/img/duck.jpg b/2014/go4java/img/duck.jpg
new file mode 100644
index 0000000..344b31e
--- /dev/null
+++ b/2014/go4java/img/duck.jpg
Binary files differ
diff --git a/2014/go4java/img/fast.jpg b/2014/go4java/img/fast.jpg
new file mode 100644
index 0000000..9b56e23
--- /dev/null
+++ b/2014/go4java/img/fast.jpg
Binary files differ
diff --git a/2014/go4java/img/funcdraw.png b/2014/go4java/img/funcdraw.png
new file mode 100644
index 0000000..374ea2e
--- /dev/null
+++ b/2014/go4java/img/funcdraw.png
Binary files differ
diff --git a/2014/go4java/img/funnelin.jpg b/2014/go4java/img/funnelin.jpg
new file mode 100644
index 0000000..2bf6873
--- /dev/null
+++ b/2014/go4java/img/funnelin.jpg
Binary files differ
diff --git a/2014/go4java/img/gopher.jpg b/2014/go4java/img/gopher.jpg
new file mode 100644
index 0000000..68795a9
--- /dev/null
+++ b/2014/go4java/img/gopher.jpg
Binary files differ
diff --git a/2014/go4java/img/lego.jpg b/2014/go4java/img/lego.jpg
new file mode 100644
index 0000000..7c77051
--- /dev/null
+++ b/2014/go4java/img/lego.jpg
Binary files differ
diff --git a/2014/go4java/img/perfection.jpg b/2014/go4java/img/perfection.jpg
new file mode 100644
index 0000000..ba57eea
--- /dev/null
+++ b/2014/go4java/img/perfection.jpg
Binary files differ
diff --git a/2014/go4java/img/piet.png b/2014/go4java/img/piet.png
new file mode 100644
index 0000000..f4856e1
--- /dev/null
+++ b/2014/go4java/img/piet.png
Binary files differ
diff --git a/2014/go4java/img/trends.png b/2014/go4java/img/trends.png
new file mode 100644
index 0000000..08dc1cf
--- /dev/null
+++ b/2014/go4java/img/trends.png
Binary files differ
diff --git a/2014/go4java/loopback.go b/2014/go4java/loopback.go
new file mode 100644
index 0000000..4574bc7
--- /dev/null
+++ b/2014/go4java/loopback.go
@@ -0,0 +1,23 @@
+package main
+
+import (
+ "bytes"
+ "net"
+)
+
+func handleConn(conn net.Conn) {
+ // does something that should be tested.
+}
+
+type loopBack struct {
+ net.Conn
+ buf bytes.Buffer
+}
+
+func (c *loopBack) Read(b []byte) (int, error) {
+ return c.buf.Read(b)
+}
+
+func (c *loopBack) Write(b []byte) (int, error) {
+ return c.buf.Write(b)
+}
diff --git a/2014/go4java/runner/embed.go b/2014/go4java/runner/embed.go
new file mode 100644
index 0000000..aef71d7
--- /dev/null
+++ b/2014/go4java/runner/embed.go
@@ -0,0 +1,25 @@
+package runner
+
+// RunCounter2 is completely equivalent to RunCounter,
+// but uses struct embedding to avoid the boilerplate of redeclaring
+// the Name method.
+type RunCounter2 struct {
+ Runner // HL
+ count int
+}
+
+func NewRunCounter2(name string) *RunCounter2 {
+ return &RunCounter2{Runner{name}, 0}
+}
+
+func (r *RunCounter2) Run(t Task) {
+ r.count++
+ r.Runner.Run(t) // HL
+}
+
+func (r *RunCounter2) RunAll(ts []Task) {
+ r.count += len(ts)
+ r.Runner.RunAll(ts) // HL
+}
+
+func (r *RunCounter2) Count() int { return r.count }
diff --git a/2014/go4java/runner/runner.go b/2014/go4java/runner/runner.go
new file mode 100644
index 0000000..1d01467
--- /dev/null
+++ b/2014/go4java/runner/runner.go
@@ -0,0 +1,55 @@
+// Package runner provides a Runner type that is used to define both RunCounter
+// and EmbeddedRunCounter to show examples of how to use composition in Go.
+package runner
+
+import "fmt"
+
+// A Task is a simple task that prints a message when run.
+type Task struct{ Msg string }
+
+func (t Task) Run() {
+ fmt.Println("running", t.Msg)
+}
+
+// END_TASK OMIT
+
+// A Runner provides a way of running tasks.
+type Runner struct{ name string }
+
+func (r *Runner) Name() string { return r.name }
+
+func (r *Runner) Run(t Task) {
+ t.Run()
+}
+
+func (r *Runner) RunAll(ts []Task) {
+ for _, t := range ts {
+ r.Run(t)
+ }
+}
+
+// END_RUNNER OMIT
+
+// A RunCounter is a Runner that keeps a counter of the run tasks.
+type RunCounter struct {
+ runner Runner // HL
+ count int
+}
+
+func NewRunCounter(name string) *RunCounter {
+ return &RunCounter{runner: Runner{name}}
+}
+
+func (r *RunCounter) Run(t Task) {
+ r.count++
+ r.runner.Run(t) // HL
+}
+
+func (r *RunCounter) RunAll(ts []Task) {
+ r.count += len(ts)
+ r.runner.RunAll(ts) // HL
+}
+
+func (r *RunCounter) Count() int { return r.count }
+
+func (r *RunCounter) Name() string { return r.runner.Name() }
diff --git a/2014/go4java/writecounter.go b/2014/go4java/writecounter.go
new file mode 100644
index 0000000..9fc9647
--- /dev/null
+++ b/2014/go4java/writecounter.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+)
+
+var (
+ _ = bytes.Buffer{}
+ _ = os.Stdout
+)
+
+// WriteCounter counts how many times `Write` is called
+type WriteCounter struct {
+ io.ReadWriter
+ count int
+}
+
+func (w *WriteCounter) Write(b []byte) (int, error) {
+ w.count += len(b)
+ return w.ReadWriter.Write(b)
+}
+
+// MAIN OMIT
+func main() {
+ buf := &bytes.Buffer{}
+ w := &WriteCounter{ReadWriter: buf}
+
+ fmt.Fprintf(w, "Hello, gophers!\n")
+ fmt.Printf("Printed %v bytes", w.count)
+}