rubyconf portugal 2014 - why ruby must go!
DESCRIPTION
In this talk, I take the audience through ha whirlwind tour of Golang for Rubyists. I also discuss things like "Programmer Awareness", what can Rubyists learn from Go and how they can co-exist.TRANSCRIPT
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
Functional
Object Oriented
Symbolic
Pascal!FORTRAN!
C
Order of execution / steps One or more subroutines
Programming Paradigms
Imperative
Declarative
Procedural
Functional
Object Oriented
Symbolic
Pascal!FORTRAN!
C!
Go Order of execution / steps One or more subroutines
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 GoingAnd learn Go along the way!
Duck Typing in Ruby
Duck Typing in RubyProgramming convenience.!Implicit Type Conversions.!No complex Type Inference
Duck Typing in RubyProgramming convenience.!Implicit Type Conversions.!No complex Type Inference
Don’t fight the Type System
Duck Typing in RubyProgramming 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 TypingNo Early Warning System!Reactive programming!Compiler Time checks!
Problems with Duck TypingNo Early Warning System!Reactive programming!Compiler Time checks!
Type Inference
Problems with Duck TypingNo 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 TypeBest of Both worlds
To Duck or to TypeLight weight 1-level Type check
To Duck or to TypeLight weight 1-level Type check
type point int !func main() { var i int = 2 var j point = 2 ! i == j }
To Duck or to TypeLight weight 1-level Type check
type point int !func main() { var i int = 2 var j point = 2 ! i == j }
Variable name first, then the type
To Duck or to TypeLight weight 1-level Type check
type point int !func main() { var i int = 2 var j point = 2 ! i == j }
To Duck or to TypeLight 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
Programmer Awareness
Programmer Awareness
Programmer Awareness
Programmer AwarenessVariable declaration and assignment
Programmer AwarenessVariable declaration and assignment
yy
Programmer AwarenessVariable declaration and assignment
y := 2 // y is of type int!y = "3"
Implicit declaration
Programmer AwarenessVariable declaration and assignment
y := 2 // y is of type int!y = "3"
Assignment
Programmer AwarenessVariable 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 AWARENESSVariable 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-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}
Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}
import packages
Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}
Exported function
Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}
Variable Re-declarationimport "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
import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}
Programmer AwarenessVariable Re-declaration
Programmer Awareness
import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! f, err := f.Stat()!}
Variable Re-declaration
Programmer Awareness
import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! f, err := f.Stat()!} Hmm.. I think you re-
used the variable f by mistake!
Variable Re-declaration
Error: no new variables on left
side of :=
import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! f, err = f.Open("other file")!}
Programmer AwarenessVariable Re-declaration
Re-assign !explicitly.. 👍
With Great Power Comes Great Responsibility
https://flic.kr/p/kSSWb
Overloadingbut 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
func main() {!! hotel := Hotel{}!! fmt.Println(hotel.Name)!!! h := make(map[string]Hotel)!!! for name, _ := range h {!! ! fmt.Println(name)!! }!}
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)!! }!}
func main() {!! hotel := Hotel{}!! fmt.Println(hotel.Name)!!! h := make(map[string]Hotel)!!! for name, _ := range h {!! ! fmt.Println(name)!! }!}
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!}
Programmer Awarenesstype 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 Awarenesstype 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 Awarenesstype 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)!! }!}
func main() {!! hotel := Hotel{}!! fmt.Println(hotel.Name)!!! h := make(map[string]Hotel)!!! for name, _ := range h {!! ! fmt.Println(name)!! }!}
Programmer Awarenesstype 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 Rubymodule 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 Rubymodule 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 AwarenessIterating a Hash
hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}
Programmer AwarenessIterating a Hash
hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}
Map of strings and Hotels
Programmer AwarenessIterating a Hash
hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}
Easy iteration syntax!
Programmer AwarenessIterating a Hash
hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!} Blank Identifier - ignore value
Programmer AwarenessIterating a Hash
hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}
Programmer AwarenessIterating 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 1Leg 2
Leg 3Leg 4
Concurrent Processing
Leg 1 Leg
2Leg
3 Leg 4
CPU churn - CPU time consuming operation.
Completion Order
Leg 1Leg 2
Leg 3Leg 4
Completion Order
Leg 1Leg 2
Leg 3Leg 4
Completion Order
Leg 1Leg 2
Leg 3Leg 4
Completion Order
Leg 1Leg 2
Leg 3Leg 4
CSP!Communicating Sequential
Processes
https://flic.kr/p/awu6ZAhttps://flic.kr/p/6MwYFo
CSP!Communicating Sequential
Processes
https://flic.kr/p/awu6ZA
since 1978 !!
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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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.. churning\n", 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 exit!! ! check_baton(leg, baton)!}
Channels in actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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.. churning\n", 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 exit!! ! check_baton(leg, baton)!}
Done for WaitGroup
Channels in actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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 actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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!! ! ! }!! ! }!}
Read or block on a channel
Channels in actionpackage 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 } return default: // ignore baton <- value } } } !func run(leg int, baton chan int) { defer wg.Done() fmt.Printf("Leg %d.. churning\n", 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 exit\n", 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?
https://flic.kr/p/9AeqD2
ConvenientToo early still.
interface{}
Keywords!
https://flic.kr/p/9AeqD2
Nah.. no rules, rules!
You need’em bro
GIL
https://flic.kr/p/9AeqD2
😪Compiled language
FTW
Extending & Embedding
https://flic.kr/p/9AeqD2
YeahNope. !
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