Why Ruby Must Go!
Why must Ruby go?
Why must Ruby go?
Why Ruby Must Go! 
What can Ruby incorporate from Go? 
What is Programmer Awareness? 
As a Rubyist, what does Go teach me?
@gautamrege 
@joshsoftware 
! 
@rubyconfindia
Programming Paradigms 
Imperative 
Declarative 
Procedural 
Functional 
Object Oriented 
Symbolic
Programming Paradigms 
Imperative 
Declarative 
Procedural 
Functional 
Object Oriented 
Symbolic 
C++! 
Java! 
Python! 
Ruby 
Order of execution / steps One or more subroutines
Programming Paradigms 
Imperative 
Declarative 
Procedural 
Order of execution / steps One or more subroutines 
Functional 
Object Oriented 
Symbolic 
Pascal! 
FORTRAN! 
C
Programming Paradigms 
Imperative 
Declarative 
Procedural 
Order of execution / steps One or more subroutines 
Functional 
Object Oriented 
Symbolic 
Pascal! 
FORTRAN! 
C! 
Go
Go Lang 
C on Steroids
Go Lang C on Steroids
Go Lang C on Steroids 
• No more memory leaks. (Garbage collection)
Go Lang C on Steroids 
• No more memory leaks. (Garbage collection) 
• No more pointer de-referencing. (-> or . )
Go Lang C on Steroids 
• No more memory leaks. (Garbage collection) 
• No more pointer de-referencing. (-> or . ) 
• Support for maps, slices and channels.
Go Lang C on Steroids 
• No more memory leaks. (Garbage collection) 
• No more pointer de-referencing. (-> or . ) 
• Support for maps, slices and channels. 
• Support for closures.
Go Lang C on Steroids 
• No more memory leaks. (Garbage collection) 
• No more pointer de-referencing. (-> or . ) 
• Support for maps, slices and channels. 
• Support for closures. 
• Concurrency: closures, channels & go-routines.
Go is different !
Go is different !
Go is different ! 
• No exceptions, only errors.
Go is different ! 
• No exceptions, only errors. 
• Return multiple values from functions
Go is different ! 
• No exceptions, only errors. 
• Return multiple values from functions 
• Interfaces but no classes (only structs)
Go is different ! 
• No exceptions, only errors. 
• Return multiple values from functions 
• Interfaces but no classes (only structs) 
• No inheritance but embedded structs
Let’s get Going 
And learn Go along the way!
Duck Typing in Ruby
Duck Typing in Ruby 
Programming convenience.! 
Implicit Type Conversions.! 
No complex Type Inference
Duck Typing in Ruby 
Programming convenience.! 
Implicit Type Conversions.! 
No complex Type Inference 
Don’t fight the Type System
Duck Typing in Ruby 
Programming convenience.! 
Implicit Type Conversions.! 
No complex Type Inference 
Don’t fight the Type System 
Code First - Resolve Issues Later
Problems with Duck Typing
Problems with Duck Typing 
No Early Warning System! 
Reactive programming! 
Compiler Time checks!
Problems with Duck Typing 
No Early Warning System! 
Reactive programming! 
Compiler Time checks! 
Type Inference
Problems with Duck Typing 
No Early Warning System! 
Reactive programming! 
Compiler Time checks! 
Type Inference 
Code Once Correctly
Types? Who cares? 
We’re ! 
Rubyists!
Types? Who cares? 
We’re ! 
Rubyists!
Type Checks in Ruby! 
def convert_hashes_to_parameters(key, value, assign_if_converted=true)! 
converted = convert_value_to_parameters(value)! 
#...! 
end! 
! 
def convert_value_to_parameters(value)! 
if value.is_a?(Array) && !converted_arrays.member?(value)! 
#...! 
converted_arrays << converted! 
converted! 
elsif value.is_a?(Parameters) || !value.is_a?(Hash)! 
#...! 
end! 
end
Type Checks in Ruby! 
def convert_hashes_to_parameters(key, value, assign_if_converted=true)! 
converted = convert_value_to_parameters(value)! 
#...! 
end! 
! 
def convert_value_to_parameters(value)! 
if value.is_a?(Array) && !converted_arrays.member?(value)! 
#...! 
converted_arrays << converted! 
converted! 
elsif value.is_a?(Parameters) || !value.is_a?(Hash)! 
#...! 
end! 
end
Type Checks in Ruby! 
def convert_hashes_to_parameters(key, value, assign_if_converted=true)! 
converted = convert_value_to_parameters(value)! 
#...! 
end! 
! 
def convert_value_to_parameters(value)! 
if value.is_a?(Array) && !converted_arrays.member?(value)! 
#...! 
converted_arrays << converted! 
converted! 
elsif value.is_a?(Parameters) || !value.is_a?(Hash)! 
#...! 
end! 
end 
def permit!! 
each_pair do |key, value|! 
value = convert_hashes_to_parameters(key, value)! 
#...! 
end
Type Checks in Ruby! 
def convert_hashes_to_parameters(key, value, assign_if_converted=true)! 
converted = convert_value_to_parameters(value)! 
#...! 
end! 
! 
def convert_value_to_parameters(value)! 
if value.is_a?(Array) && !converted_arrays.member?(value)! 
#...! 
converted_arrays << converted! 
converted! 
elsif value.is_a?(Parameters) || !value.is_a?(Hash)! 
#...! 
end! 
end 
def permit!! 
each_pair do |key, value|! 
value = convert_hashes_to_parameters(key, value)! 
#...! 
end 
Strong Parameters!
To Duck or to Type
To Duck or to Type 
Best of Both worlds
To Duck or to Type 
Light weight 1-level Type check
To Duck or to Type 
Light weight 1-level Type check 
type point int 
! 
func main() { 
var i int = 2 
var j point = 2 
! 
i == j 
}
To Duck or to Type 
Light weight 1-level Type check 
type point int 
! 
func main() { 
var i int = 2 
var j point = 2 
Variable name first, then the type 
! 
i == j 
}
To Duck or to Type 
Light weight 1-level Type check 
type point int 
! 
func main() { 
var i int = 2 
var j point = 2 
! 
i == j 
}
To Duck or to Type 
Light weight 1-level Type check 
type point int 
! 
func main() { 
var i int = 2 
var j point = 2 
! 
i == j 
} 
Error: invalid operation: i == j 
(mismatched types int and point)
Ruby re-defines Object 
Oriented Concepts, 
Go re-defines 
programming itself! 
“ 
”
Programmer Awareness
Programmer Awareness 
%QORKNGT
Programmer Awareness 
%QORKNGT 
4GXKGYGT
Programmer Awareness 
%QORKNGT 
4GXKGYGT 
(TCOGYQTM
Programmer Awareness 
%QORKNGT 
4GXKGYGT 
(TCOGYQTM 
.CPIWCIG
Programmer Awareness 
Variable declaration and assignment
Programmer Awareness 
Variable declaration and assignment 
y 
y
Programmer Awareness 
Variable declaration and assignment 
y := 2 // y is of type int! 
y = "3" 
Implicit declaration
Programmer Awareness 
Variable declaration and assignment 
y := 2 // y is of type int! 
y = "3" 
Assignment
Programmer Awareness 
Variable declaration and assignment 
y := 2 // y is of type int! 
y = "3" 
COMPLIER ERROR! 
cannot use “3” (type string) as type int in 
assignment
Programmer ERROR? 
Variable declaration and assignment 
y := 2 // y is of type int! 
y = "3" 
As a programmer, we probably re-assigned 
“y” to a String by mistake!
Programmer AWARENESS 
Variable declaration and assignment 
y := 2 // y is of type int! 
y, _ = strconv.Atoi("3") 
There’s always a right way to do things!
! 
Eh… what?
! 
Eh… what? 
https://flic.kr/p/mnZgQw
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
}
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
} 
import packages
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
} 
Exported function
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
}
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
} 
I’m practical. You 
can re-declare err in your 
code!* 
* Conditions apply
Programmer Awareness 
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! d, err := f.Stat()! 
}
Programmer Awareness 
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! f, err := f.Stat()! 
}
Programmer Awareness 
Variable Re-declaration 
import "os"! 
Error: no new 
! 
variables on left 
func main() {! 
side of := 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! f, err := f.Stat()! 
} Hmm.. I think you re-used 
the variable f by 
mistake!
Programmer Awareness 
Variable Re-declaration 
import "os"! 
! 
func main() {! 
! f, err := os.Open("somefile")! 
! // handle error! 
! 
! f, err = f.Open("other file")! 
} 
Re-assign ! 
explicitly.. 
With Great Power Comes 
Great Responsibility
https://flic.kr/p/kSSWb
Overloading 
but first …
Lets Go a little more! 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Dimensions)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
Type Declaration
Lets Go a little more! 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Dimensions)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
Exported Array
Lets Go a little more! 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Dimensions)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
Exported Array 
The size in Array is part of the type! 
[2]float32 != [3]float32
Lets Go a little more! 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Dimensions)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
Embedding! 
(Not inheritance)
Lets Go a little more! 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Dimensions)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
hotel.Dimensions and not 
hotel.Hall.Dimensions
Lets Go a little more! 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
Dimensions)!
Lets Go a little more! 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
}
Programmer Awareness 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
}
Programmer Awareness 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
} 
Which Name should 
I use? 
Error: Ambiguous 
selector hotel.Name!
Programmer Awareness 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Name)Hall.! 
Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
}
Programmer Awareness 
type Layout struct {! 
! Name string! 
Capacity int! 
}! 
! 
type Hall struct {! 
! Name string! 
! Dimensions [2]float32! 
}! 
! 
type Hotel struct {! 
! Location string! 
! Hall! 
! Layout! 
} 
func main() {! 
! hotel := Hotel{}! 
! fmt.Println(hotel.Hall.Name)! 
! 
! h := make(map[string]Hotel)! 
! 
! for name, _ := range h {! 
! ! fmt.Println(name)! 
! }! 
}
Modules in Ruby 
module Layout! 
def manager! 
p "Layout Manager"! 
end! 
end! 
! 
module Hall! 
def manager! 
p "Hall Manager"! 
end! 
end! 
! 
class Hotel! 
include Layout! 
include Hall! 
end 
def main! 
hotel = Hotel.new! 
p hotel.manager! 
end
Modules in Ruby 
module Layout! 
def manager! 
p "Layout Manager"! 
end! 
end! 
! 
module Hall! 
def manager! 
p "Hall Manager"! 
end! 
end! 
! 
class Hotel! 
include Layout! 
include Hall! 
end 
def main! 
hotel = Hotel.new! 
p hotel.manager! 
end 
Which language is 
this dude?
Include modules 
in order! 
https://flic.kr/p/e7SnAa
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
}
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
} 
Map of strings and Hotels
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
} 
Easy iteration syntax!
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
} Blank Identifier - ignore value
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
}
Programmer Awareness 
Iterating a Hash 
hotels := make(map[string]Hotel)! 
! 
for name, _ := range hotels {! 
! fmt.Println(name)! 
} 
Bad practice! ! 
I’ll randomise the 
order!
Ordered Hashes!
Ordered Hashes!
Pushing some 
Goodies into Ruby 
https://flic.kr/p/awu6ZA
Defer 
mu sync.Mutex! 
! 
func foo() {! 
mu.Lock()! 
defer mu.unLock()! 
// do something...! 
} 
https://flic.kr/p/awu6ZA
Defer 
func trace(s string) { fmt.Println("entering:", s) }! 
func untrace(s string) { fmt.Println("leaving:", s) }! 
! 
func a() {! 
trace("a")! 
defer untrace("a")! 
// do something....! 
} 
https://flic.kr/p/awu6ZA
Concurrency 
Parallelism 
Multi-core Processing 
https://flic.kr/p/awu6ZA
Example - Relay Race 
• 4 legs of the race 
• Each leg does processing concurrently. 
• Completion should be in order. (pass the baton)
Concurrent Example 
Leg 1 
Leg 2 
Leg 3 
Leg 4
Concurrent Processing 
Leg 
1 
Leg 
2 
Leg 
3 Leg 
4 
CPU churn - CPU time 
consuming operation.
Completion Order 
Leg 1 
Leg 2 
Leg 3 
Leg 4
Completion Order 
Leg 1 
Leg 2 
Leg 3 
Leg 4
Completion Order 
Leg 1 
Leg 2 
Leg 3 
Leg 4
Completion Order 
Leg 1 
Leg 2 
Leg 3 
Leg 4
CSP! 
Communicating Sequential 
Processes 
https://flic.kr/p/6MwYFo https://flic.kr/p/awu6ZA
CSP! 
Communicating Sequential 
Processes 
since 1978 !! 
https://flic.kr/p/awu6ZA 
https://flic.kr/p/6MwYFo
package main 
! 
import ( 
"fmt" 
"runtime" 
"sync" 
) 
! 
var wg sync.WaitGroup 
! 
/* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func main() { 
runtime.GOMAXPROCS(4) 
! 
baton := make(chan int) 
wg.Add(4) 
! 
for i := 1; i < 5; i++ {! 
go run(i, baton)! 
}! 
! 
! ! ! // start the race! 
baton <- 1! 
! 
// wait for relay to finish! 
wg.Wait()! 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func main() { 
runtime.GOMAXPROCS(4) 
! 
baton := make(chan int) 
wg.Add(4) 
! 
for i := 1; i < 5; i++ {! 
go run(i, baton)! 
}! 
! 
! ! ! // start the race! 
baton <- 1! 
! 
// wait for relay to finish! 
wg.Wait()! 
} 
A channel that accepts an int
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func main() { 
runtime.GOMAXPROCS(4) 
! 
baton := make(chan int) 
wg.Add(4) 
! 
for i := 1; i < 5; i++ {! 
go run(i, baton)! 
}! 
! 
! ! ! // start the race! 
baton <- 1! 
! 
// wait for relay to finish! 
wg.Wait()! 
} 
Go Routine
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func main() { 
runtime.GOMAXPROCS(4) 
! 
baton := make(chan int) 
wg.Add(4) 
! 
for i := 1; i < 5; i++ {! 
go run(i, baton)! 
}! 
! 
! ! ! // start the race! 
baton <- 1! 
! 
// wait for relay to finish! 
wg.Wait()! 
} 
Writing to a channel
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func main() { 
runtime.GOMAXPROCS(4) 
! 
baton := make(chan int) 
wg.Add(4) 
! 
for i := 1; i < 5; i++ {! 
go run(i, baton)! 
}! 
! 
! ! ! // start the race! 
baton <- 1! 
! 
// wait for relay to finish! 
wg.Wait()! 
} 
A WaitGroup - wait 
for 4 events!
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func run(leg int, baton chan int) { 
defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) 
! 
! ! // Massive CPU churn! 
! ! for count := 0; count < 300; count++ {! 
! ! ! for char := 0; char < 30000; char++ {! ! ! ! fmt.Printf("")! 
! ! ! }! 
! ! }! 
fmt.Printf("Leg %d.. churned, waiting to ! 
! ! check_baton(leg, baton)! 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func run(leg int, baton chan int) { 
defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) 
Done for WaitGroup 
! 
! ! // Massive CPU churn! 
! ! for count := 0; count < 300; count++ {! 
! ! ! for char := 0; char < 30000; char++ {! ! ! ! fmt.Printf("")! 
! ! ! }! 
! ! }! 
fmt.Printf("Leg %d.. churned, waiting to ! 
! ! check_baton(leg, baton)! 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func check_baton(leg int, baton chan int) {! 
! ! for value := range baton {! 
! ! ! switch value {! 
! ! ! ! case leg:! 
! ! ! ! ! // pass the baton! 
! ! ! ! ! fmt.Println("Finished leg ", leg)! 
! ! ! ! ! if leg == 4 {! 
! ! ! ! ! ! close(baton)! 
! ! ! ! ! } else {! 
! ! ! ! ! ! ! baton <- leg + 1! 
! ! ! ! ! }! 
! ! ! ! ! return! 
! ! ! ! default:! 
! ! ! ! ! // ignore! 
! ! ! ! ! baton <- value! 
! ! ! }! 
! ! }! 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func check_baton(leg int, baton chan int) {! 
! ! for value := range baton {! 
! ! ! switch value {! 
! ! ! ! case leg:Read ! 
or block on a 
! ! ! ! ! // pass the channel 
baton! 
! ! ! ! ! fmt.Println("Finished leg ", leg)! 
! ! ! ! ! if leg == 4 {! 
! ! ! ! ! ! close(baton)! 
! ! ! ! ! } else {! 
! ! ! ! ! ! ! baton <- leg + 1! 
! ! ! ! ! }! 
! ! ! ! ! return! 
! ! ! ! default:! 
! ! ! ! ! // ignore! 
! ! ! ! ! baton <- value! 
! ! ! }! 
! ! }! 
}
Channels in action 
p!ackage main import ( 
"fmt" 
"runtime" 
"sync" 
)! v!ar wg sync.WaitGroup /* 
* Each go-routine sleeps at random(1-5) seconds. 
* This is simulating long working process 
* Then we finish in order 
*/ 
func check_baton(leg int, baton chan int) { 
for value := range baton { 
switch value { 
case leg: 
// pass the baton 
fmt.Println("Finished leg ", leg) 
if leg == 4 { 
close(baton) 
} else { 
baton <- leg + 1 
} 
return 
default: 
// ignore 
baton <- value 
} 
} 
}! func run(leg int, baton chan int) { 
! defer wg.Done() 
fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn 
for count := 0; count < 300; count++ { 
for char := 0; char < 30000; char++ { 
fmt.Printf("") 
} 
! } 
fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) 
}! func main() { 
runtime.GOMAXPROCS(4) ! baton := make(chan int) 
wg.Add(4) for i := 1; i < 5; i++ { 
! go run(i, baton) 
} ! // start the race 
baton <- 1 // wait for relay to finish 
wg.Wait() 
} 
func check_baton(leg int, baton chan int) {! 
! ! for value := range baton {! 
! ! ! switch value {! 
! ! ! ! case leg:! 
! ! ! ! ! // pass the baton! 
! ! ! ! ! fmt.Println("Finished leg ", leg)! 
! ! ! ! ! if leg == 4 {! 
! ! ! ! ! ! close(baton)! 
! ! ! ! ! } else {! 
! ! ! ! ! ! ! baton <- leg + 1! 
! ! ! ! ! }! 
! ! ! ! ! return! 
! ! ! ! default:! 
! ! ! ! ! // ignore! 
! ! ! ! ! baton <- value! 
! ! ! }! 
! ! }! 
}
The Big Fight 
https://flic.kr/p/9AeqD2
Generics? 
Convenient 
Too early still. 
interface{} 
https://flic.kr/p/9AeqD2
Keywords! 
Nah.. no rules, 
https://flic.kr/p/9AeqD2 
rules! 
You need’em 
bro
GIL 
https://flic.kr/p/9AeqD2 
 
Compiled 
language 
FTW
Extending & Embedding 
https://flic.kr/p/9AeqD2 
Yeah 
Nope. ! 
Only Cgo
Tooling 
https://flic.kr/p/9AeqD2 
gem 
bundler 
go tools
Emergency Instructions ! 
OR ! 
Lecture In Aerodynamics
Emergency Instructions
Emergency Instructions
Traction Control! 
Fuel Efficiency! 
Aerodynamics! 
Tyre Temperature
Traction Control! 
Fuel Efficiency! 
Aerodynamics! 
Tyre Temperature
“ Ruby is for developers 
Go is for programmers 
” 
@gautamrege 
@joshsoftware

RubyConf Portugal 2014 - Why ruby must go!

  • 1.
  • 2.
  • 3.
  • 4.
    Why Ruby MustGo! What can Ruby incorporate from Go? What is Programmer Awareness? As a Rubyist, what does Go teach me?
  • 5.
  • 6.
    Programming Paradigms Imperative Declarative Procedural Functional Object Oriented Symbolic
  • 7.
    Programming Paradigms Imperative Declarative Procedural Functional Object Oriented Symbolic C++! Java! Python! Ruby Order of execution / steps One or more subroutines
  • 8.
    Programming Paradigms Imperative Declarative Procedural Order of execution / steps One or more subroutines Functional Object Oriented Symbolic Pascal! FORTRAN! C
  • 9.
    Programming Paradigms Imperative Declarative Procedural Order of execution / steps One or more subroutines Functional Object Oriented Symbolic Pascal! FORTRAN! C! Go
  • 10.
    Go Lang Con Steroids
  • 11.
    Go Lang Con Steroids
  • 12.
    Go Lang Con Steroids • No more memory leaks. (Garbage collection)
  • 13.
    Go Lang Con Steroids • No more memory leaks. (Garbage collection) • No more pointer de-referencing. (-> or . )
  • 14.
    Go Lang Con Steroids • No more memory leaks. (Garbage collection) • No more pointer de-referencing. (-> or . ) • Support for maps, slices and channels.
  • 15.
    Go Lang Con Steroids • No more memory leaks. (Garbage collection) • No more pointer de-referencing. (-> or . ) • Support for maps, slices and channels. • Support for closures.
  • 16.
    Go Lang Con Steroids • No more memory leaks. (Garbage collection) • No more pointer de-referencing. (-> or . ) • Support for maps, slices and channels. • Support for closures. • Concurrency: closures, channels & go-routines.
  • 17.
  • 18.
  • 19.
    Go is different! • No exceptions, only errors.
  • 20.
    Go is different! • No exceptions, only errors. • Return multiple values from functions
  • 21.
    Go is different! • No exceptions, only errors. • Return multiple values from functions • Interfaces but no classes (only structs)
  • 22.
    Go is different! • No exceptions, only errors. • Return multiple values from functions • Interfaces but no classes (only structs) • No inheritance but embedded structs
  • 23.
    Let’s get Going And learn Go along the way!
  • 24.
  • 25.
    Duck Typing inRuby Programming convenience.! Implicit Type Conversions.! No complex Type Inference
  • 26.
    Duck Typing inRuby Programming convenience.! Implicit Type Conversions.! No complex Type Inference Don’t fight the Type System
  • 27.
    Duck Typing inRuby Programming convenience.! Implicit Type Conversions.! No complex Type Inference Don’t fight the Type System Code First - Resolve Issues Later
  • 28.
  • 29.
    Problems with DuckTyping No Early Warning System! Reactive programming! Compiler Time checks!
  • 30.
    Problems with DuckTyping No Early Warning System! Reactive programming! Compiler Time checks! Type Inference
  • 31.
    Problems with DuckTyping No Early Warning System! Reactive programming! Compiler Time checks! Type Inference Code Once Correctly
  • 32.
    Types? Who cares? We’re ! Rubyists!
  • 33.
    Types? Who cares? We’re ! Rubyists!
  • 34.
    Type Checks inRuby! def convert_hashes_to_parameters(key, value, assign_if_converted=true)! converted = convert_value_to_parameters(value)! #...! end! ! def convert_value_to_parameters(value)! if value.is_a?(Array) && !converted_arrays.member?(value)! #...! converted_arrays << converted! converted! elsif value.is_a?(Parameters) || !value.is_a?(Hash)! #...! end! end
  • 35.
    Type Checks inRuby! def convert_hashes_to_parameters(key, value, assign_if_converted=true)! converted = convert_value_to_parameters(value)! #...! end! ! def convert_value_to_parameters(value)! if value.is_a?(Array) && !converted_arrays.member?(value)! #...! converted_arrays << converted! converted! elsif value.is_a?(Parameters) || !value.is_a?(Hash)! #...! end! end
  • 36.
    Type Checks inRuby! def convert_hashes_to_parameters(key, value, assign_if_converted=true)! converted = convert_value_to_parameters(value)! #...! end! ! def convert_value_to_parameters(value)! if value.is_a?(Array) && !converted_arrays.member?(value)! #...! converted_arrays << converted! converted! elsif value.is_a?(Parameters) || !value.is_a?(Hash)! #...! end! end def permit!! each_pair do |key, value|! value = convert_hashes_to_parameters(key, value)! #...! end
  • 37.
    Type Checks inRuby! def convert_hashes_to_parameters(key, value, assign_if_converted=true)! converted = convert_value_to_parameters(value)! #...! end! ! def convert_value_to_parameters(value)! if value.is_a?(Array) && !converted_arrays.member?(value)! #...! converted_arrays << converted! converted! elsif value.is_a?(Parameters) || !value.is_a?(Hash)! #...! end! end def permit!! each_pair do |key, value|! value = convert_hashes_to_parameters(key, value)! #...! end Strong Parameters!
  • 38.
    To Duck orto Type
  • 39.
    To Duck orto Type Best of Both worlds
  • 40.
    To Duck orto Type Light weight 1-level Type check
  • 41.
    To Duck orto Type Light weight 1-level Type check type point int ! func main() { var i int = 2 var j point = 2 ! i == j }
  • 42.
    To Duck orto Type Light weight 1-level Type check type point int ! func main() { var i int = 2 var j point = 2 Variable name first, then the type ! i == j }
  • 43.
    To Duck orto Type Light weight 1-level Type check type point int ! func main() { var i int = 2 var j point = 2 ! i == j }
  • 44.
    To Duck orto Type Light weight 1-level Type check type point int ! func main() { var i int = 2 var j point = 2 ! i == j } Error: invalid operation: i == j (mismatched types int and point)
  • 45.
    Ruby re-defines Object Oriented Concepts, Go re-defines programming itself! “ ”
  • 46.
  • 47.
  • 48.
  • 49.
    Programmer Awareness %QORKNGT 4GXKGYGT (TCOGYQTM
  • 50.
    Programmer Awareness %QORKNGT 4GXKGYGT (TCOGYQTM .CPIWCIG
  • 51.
    Programmer Awareness Variabledeclaration and assignment
  • 52.
    Programmer Awareness Variabledeclaration and assignment y y
  • 53.
    Programmer Awareness Variabledeclaration and assignment y := 2 // y is of type int! y = "3" Implicit declaration
  • 54.
    Programmer Awareness Variabledeclaration and assignment y := 2 // y is of type int! y = "3" Assignment
  • 55.
    Programmer Awareness Variabledeclaration and assignment y := 2 // y is of type int! y = "3" COMPLIER ERROR! cannot use “3” (type string) as type int in assignment
  • 56.
    Programmer ERROR? Variabledeclaration and assignment y := 2 // y is of type int! y = "3" As a programmer, we probably re-assigned “y” to a String by mistake!
  • 57.
    Programmer AWARENESS Variabledeclaration and assignment y := 2 // y is of type int! y, _ = strconv.Atoi("3") There’s always a right way to do things!
  • 58.
  • 59.
    ! Eh… what? https://flic.kr/p/mnZgQw
  • 60.
    Variable Re-declaration import"os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! }
  • 61.
    Variable Re-declaration import"os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! } import packages
  • 62.
    Variable Re-declaration import"os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! } Exported function
  • 63.
    Variable Re-declaration import"os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! }
  • 64.
    Variable Re-declaration import"os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! } I’m practical. You can re-declare err in your code!* * Conditions apply
  • 65.
    Programmer Awareness VariableRe-declaration import "os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! d, err := f.Stat()! }
  • 66.
    Programmer Awareness VariableRe-declaration import "os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! f, err := f.Stat()! }
  • 67.
    Programmer Awareness VariableRe-declaration import "os"! Error: no new ! variables on left func main() {! side of := ! f, err := os.Open("somefile")! ! // handle error! ! ! f, err := f.Stat()! } Hmm.. I think you re-used the variable f by mistake!
  • 68.
    Programmer Awareness VariableRe-declaration import "os"! ! func main() {! ! f, err := os.Open("somefile")! ! // handle error! ! ! f, err = f.Open("other file")! } Re-assign ! explicitly.. 
  • 70.
    With Great PowerComes Great Responsibility
  • 71.
  • 72.
  • 73.
    Lets Go alittle more! type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Dimensions)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } Type Declaration
  • 74.
    Lets Go alittle more! type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Dimensions)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } Exported Array
  • 75.
    Lets Go alittle more! type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Dimensions)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } Exported Array The size in Array is part of the type! [2]float32 != [3]float32
  • 76.
    Lets Go alittle more! type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Dimensions)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } Embedding! (Not inheritance)
  • 77.
    Lets Go alittle more! type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Dimensions)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } hotel.Dimensions and not hotel.Hall.Dimensions
  • 78.
    Lets Go alittle more! func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } Dimensions)!
  • 79.
    Lets Go alittle more! func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } type Layout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! }
  • 80.
    Programmer Awareness typeLayout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! }
  • 81.
    Programmer Awareness typeLayout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! } Which Name should I use? Error: Ambiguous selector hotel.Name!
  • 82.
    Programmer Awareness typeLayout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Name)Hall.! Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! }
  • 83.
    Programmer Awareness typeLayout struct {! ! Name string! Capacity int! }! ! type Hall struct {! ! Name string! ! Dimensions [2]float32! }! ! type Hotel struct {! ! Location string! ! Hall! ! Layout! } func main() {! ! hotel := Hotel{}! ! fmt.Println(hotel.Hall.Name)! ! ! h := make(map[string]Hotel)! ! ! for name, _ := range h {! ! ! fmt.Println(name)! ! }! }
  • 84.
    Modules in Ruby module Layout! def manager! p "Layout Manager"! end! end! ! module Hall! def manager! p "Hall Manager"! end! end! ! class Hotel! include Layout! include Hall! end def main! hotel = Hotel.new! p hotel.manager! end
  • 85.
    Modules in Ruby module Layout! def manager! p "Layout Manager"! end! end! ! module Hall! def manager! p "Hall Manager"! end! end! ! class Hotel! include Layout! include Hall! end def main! hotel = Hotel.new! p hotel.manager! end Which language is this dude?
  • 86.
    Include modules inorder! https://flic.kr/p/e7SnAa
  • 87.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! }
  • 88.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! } Map of strings and Hotels
  • 89.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! } Easy iteration syntax!
  • 90.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! } Blank Identifier - ignore value
  • 91.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! }
  • 92.
    Programmer Awareness Iteratinga Hash hotels := make(map[string]Hotel)! ! for name, _ := range hotels {! ! fmt.Println(name)! } Bad practice! ! I’ll randomise the order!
  • 93.
  • 94.
  • 95.
    Pushing some Goodiesinto Ruby https://flic.kr/p/awu6ZA
  • 96.
    Defer mu sync.Mutex! ! func foo() {! mu.Lock()! defer mu.unLock()! // do something...! } https://flic.kr/p/awu6ZA
  • 97.
    Defer func trace(sstring) { fmt.Println("entering:", s) }! func untrace(s string) { fmt.Println("leaving:", s) }! ! func a() {! trace("a")! defer untrace("a")! // do something....! } https://flic.kr/p/awu6ZA
  • 98.
    Concurrency Parallelism Multi-coreProcessing https://flic.kr/p/awu6ZA
  • 99.
    Example - RelayRace • 4 legs of the race • Each leg does processing concurrently. • Completion should be in order. (pass the baton)
  • 100.
    Concurrent Example Leg1 Leg 2 Leg 3 Leg 4
  • 101.
    Concurrent Processing Leg 1 Leg 2 Leg 3 Leg 4 CPU churn - CPU time consuming operation.
  • 102.
    Completion Order Leg1 Leg 2 Leg 3 Leg 4
  • 103.
    Completion Order Leg1 Leg 2 Leg 3 Leg 4
  • 104.
    Completion Order Leg1 Leg 2 Leg 3 Leg 4
  • 105.
    Completion Order Leg1 Leg 2 Leg 3 Leg 4
  • 108.
    CSP! Communicating Sequential Processes https://flic.kr/p/6MwYFo https://flic.kr/p/awu6ZA
  • 109.
    CSP! Communicating Sequential Processes since 1978 !! https://flic.kr/p/awu6ZA https://flic.kr/p/6MwYFo
  • 110.
    package main ! import ( "fmt" "runtime" "sync" ) ! var wg sync.WaitGroup ! /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1
  • 111.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() }
  • 112.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) ! for i := 1; i < 5; i++ {! go run(i, baton)! }! ! ! ! ! // start the race! baton <- 1! ! // wait for relay to finish! wg.Wait()! }
  • 113.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) ! for i := 1; i < 5; i++ {! go run(i, baton)! }! ! ! ! ! // start the race! baton <- 1! ! // wait for relay to finish! wg.Wait()! } A channel that accepts an int
  • 114.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) ! for i := 1; i < 5; i++ {! go run(i, baton)! }! ! ! ! ! // start the race! baton <- 1! ! // wait for relay to finish! wg.Wait()! } Go Routine
  • 115.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) ! for i := 1; i < 5; i++ {! go run(i, baton)! }! ! ! ! ! // start the race! baton <- 1! ! // wait for relay to finish! wg.Wait()! } Writing to a channel
  • 116.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) ! for i := 1; i < 5; i++ {! go run(i, baton)! }! ! ! ! ! // start the race! baton <- 1! ! // wait for relay to finish! wg.Wait()! } A WaitGroup - wait for 4 events!
  • 117.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() }
  • 118.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) ! ! ! // Massive CPU churn! ! ! for count := 0; count < 300; count++ {! ! ! ! for char := 0; char < 30000; char++ {! ! ! ! fmt.Printf("")! ! ! ! }! ! ! }! fmt.Printf("Leg %d.. churned, waiting to ! ! ! check_baton(leg, baton)! }
  • 119.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) Done for WaitGroup ! ! ! // Massive CPU churn! ! ! for count := 0; count < 300; count++ {! ! ! ! for char := 0; char < 30000; char++ {! ! ! ! fmt.Printf("")! ! ! ! }! ! ! }! fmt.Printf("Leg %d.. churned, waiting to ! ! ! check_baton(leg, baton)! }
  • 120.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() }
  • 121.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func check_baton(leg int, baton chan int) {! ! ! for value := range baton {! ! ! ! switch value {! ! ! ! ! case leg:! ! ! ! ! ! // pass the baton! ! ! ! ! ! fmt.Println("Finished leg ", leg)! ! ! ! ! ! if leg == 4 {! ! ! ! ! ! ! close(baton)! ! ! ! ! ! } else {! ! ! ! ! ! ! ! baton <- leg + 1! ! ! ! ! ! }! ! ! ! ! ! return! ! ! ! ! default:! ! ! ! ! ! // ignore! ! ! ! ! ! baton <- value! ! ! ! }! ! ! }! }
  • 122.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func check_baton(leg int, baton chan int) {! ! ! for value := range baton {! ! ! ! switch value {! ! ! ! ! case leg:Read ! or block on a ! ! ! ! ! // pass the channel baton! ! ! ! ! ! fmt.Println("Finished leg ", leg)! ! ! ! ! ! if leg == 4 {! ! ! ! ! ! ! close(baton)! ! ! ! ! ! } else {! ! ! ! ! ! ! ! baton <- leg + 1! ! ! ! ! ! }! ! ! ! ! ! return! ! ! ! ! default:! ! ! ! ! ! // ignore! ! ! ! ! ! baton <- value! ! ! ! }! ! ! }! }
  • 123.
    Channels in action p!ackage main import ( "fmt" "runtime" "sync" )! v!ar wg sync.WaitGroup /* * Each go-routine sleeps at random(1-5) seconds. * This is simulating long working process * Then we finish in order */ func check_baton(leg int, baton chan int) { for value := range baton { switch value { case leg: // pass the baton fmt.Println("Finished leg ", leg) if leg == 4 { close(baton) } else { baton <- leg + 1 } return default: // ignore baton <- value } } }! func run(leg int, baton chan int) { ! defer wg.Done() fmt.Printf("Leg %d.. churningn", leg) // Massive CPU churn for count := 0; count < 300; count++ { for char := 0; char < 30000; char++ { fmt.Printf("") } ! } fmt.Printf("Leg %d.. churned, waiting to exitn", leg) ! check_baton(leg, baton) }! func main() { runtime.GOMAXPROCS(4) ! baton := make(chan int) wg.Add(4) for i := 1; i < 5; i++ { ! go run(i, baton) } ! // start the race baton <- 1 // wait for relay to finish wg.Wait() } func check_baton(leg int, baton chan int) {! ! ! for value := range baton {! ! ! ! switch value {! ! ! ! ! case leg:! ! ! ! ! ! // pass the baton! ! ! ! ! ! fmt.Println("Finished leg ", leg)! ! ! ! ! ! if leg == 4 {! ! ! ! ! ! ! close(baton)! ! ! ! ! ! } else {! ! ! ! ! ! ! ! baton <- leg + 1! ! ! ! ! ! }! ! ! ! ! ! return! ! ! ! ! default:! ! ! ! ! ! // ignore! ! ! ! ! ! baton <- value! ! ! ! }! ! ! }! }
  • 124.
    The Big Fight https://flic.kr/p/9AeqD2
  • 125.
    Generics? Convenient Tooearly still. interface{} https://flic.kr/p/9AeqD2
  • 126.
    Keywords! Nah.. norules, https://flic.kr/p/9AeqD2 rules! You need’em bro
  • 127.
    GIL https://flic.kr/p/9AeqD2  Compiled language FTW
  • 128.
    Extending & Embedding https://flic.kr/p/9AeqD2 Yeah Nope. ! Only Cgo
  • 129.
  • 131.
    Emergency Instructions ! OR ! Lecture In Aerodynamics
  • 132.
  • 133.
  • 135.
    Traction Control! FuelEfficiency! Aerodynamics! Tyre Temperature
  • 136.
    Traction Control! FuelEfficiency! Aerodynamics! Tyre Temperature
  • 137.
    “ Ruby isfor developers Go is for programmers ” @gautamrege @joshsoftware