rubyconf portugal 2014 - why ruby must go!

137
Why Ruby Must Go!

Upload: gautam-rege

Post on 18-Nov-2014

2.880 views

Category:

Software


3 download

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

Page 1: RubyConf Portugal 2014 - Why ruby must go!

Why Ruby Must Go!

Page 2: RubyConf Portugal 2014 - Why ruby must go!

Why must Ruby go?

Page 3: RubyConf Portugal 2014 - Why ruby must go!

Why must Ruby go?

Page 4: RubyConf Portugal 2014 - Why ruby must go!

Why Ruby Must Go!What can Ruby incorporate from Go?

What is Programmer Awareness?

As a Rubyist, what does Go teach me?

Page 5: RubyConf Portugal 2014 - Why ruby must go!

@gautamrege @joshsoftware

!

@rubyconfindia

Page 6: RubyConf Portugal 2014 - Why ruby must go!

Programming Paradigms

Imperative

Declarative

Procedural

Functional

Object Oriented

Symbolic

Page 7: RubyConf Portugal 2014 - Why ruby must go!

Programming Paradigms

Imperative

Declarative

Procedural

Functional

Object Oriented

Symbolic

C++!Java!Python!Ruby

Order of execution / steps One or more subroutines

Page 8: RubyConf Portugal 2014 - Why ruby must go!

Programming Paradigms

Imperative

Declarative

Procedural

Functional

Object Oriented

Symbolic

Pascal!FORTRAN!

C

Order of execution / steps One or more subroutines

Page 9: RubyConf Portugal 2014 - Why ruby must go!

Programming Paradigms

Imperative

Declarative

Procedural

Functional

Object Oriented

Symbolic

Pascal!FORTRAN!

C!

Go Order of execution / steps One or more subroutines

Page 10: RubyConf Portugal 2014 - Why ruby must go!

Go Lang

C on Steroids

Page 11: RubyConf Portugal 2014 - Why ruby must go!

Go Lang C on Steroids

Page 12: RubyConf Portugal 2014 - Why ruby must go!

Go Lang C on Steroids• No more memory leaks. (Garbage collection)

Page 13: RubyConf Portugal 2014 - Why ruby must go!

Go Lang C on Steroids• No more memory leaks. (Garbage collection)

• No more pointer de-referencing. (-> or . )

Page 14: RubyConf Portugal 2014 - Why ruby must go!

Go Lang C on Steroids• No more memory leaks. (Garbage collection)

• No more pointer de-referencing. (-> or . )

• Support for maps, slices and channels.

Page 15: RubyConf Portugal 2014 - Why ruby must go!

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.

Page 16: RubyConf Portugal 2014 - Why ruby must go!

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.

Page 17: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

Page 18: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

Page 19: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

• No exceptions, only errors.

Page 20: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

• No exceptions, only errors.

• Return multiple values from functions

Page 21: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

• No exceptions, only errors.

• Return multiple values from functions

• Interfaces but no classes (only structs)

Page 22: RubyConf Portugal 2014 - Why ruby must go!

Go is different !

• No exceptions, only errors.

• Return multiple values from functions

• Interfaces but no classes (only structs)

• No inheritance but embedded structs

Page 23: RubyConf Portugal 2014 - Why ruby must go!

Let’s get GoingAnd learn Go along the way!

Page 24: RubyConf Portugal 2014 - Why ruby must go!

Duck Typing in Ruby

Page 25: RubyConf Portugal 2014 - Why ruby must go!

Duck Typing in RubyProgramming convenience.!Implicit Type Conversions.!No complex Type Inference

Page 26: RubyConf Portugal 2014 - Why ruby must go!

Duck Typing in RubyProgramming convenience.!Implicit Type Conversions.!No complex Type Inference

Don’t fight the Type System

Page 27: RubyConf Portugal 2014 - Why ruby must go!

Duck Typing in RubyProgramming convenience.!Implicit Type Conversions.!No complex Type Inference

Don’t fight the Type System

Code First - Resolve Issues Later

Page 28: RubyConf Portugal 2014 - Why ruby must go!

Problems with Duck Typing

Page 29: RubyConf Portugal 2014 - Why ruby must go!

Problems with Duck TypingNo Early Warning System!Reactive programming!Compiler Time checks!

Page 30: RubyConf Portugal 2014 - Why ruby must go!

Problems with Duck TypingNo Early Warning System!Reactive programming!Compiler Time checks!

Type Inference

Page 31: RubyConf Portugal 2014 - Why ruby must go!

Problems with Duck TypingNo Early Warning System!Reactive programming!Compiler Time checks!

Type Inference

Code Once Correctly

Page 32: RubyConf Portugal 2014 - Why ruby must go!

Types? Who cares?

We’re !Rubyists!

Page 33: RubyConf Portugal 2014 - Why ruby must go!

Types? Who cares?

We’re !Rubyists!

Page 34: RubyConf Portugal 2014 - Why ruby must go!

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

Page 35: RubyConf Portugal 2014 - Why ruby must go!

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

Page 36: RubyConf Portugal 2014 - Why ruby must go!

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

Page 37: RubyConf Portugal 2014 - Why ruby must go!

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!

Page 38: RubyConf Portugal 2014 - Why ruby must go!

To Duck or to Type

Page 39: RubyConf Portugal 2014 - Why ruby must go!

To Duck or to TypeBest of Both worlds

Page 40: RubyConf Portugal 2014 - Why ruby must go!

To Duck or to TypeLight weight 1-level Type check

Page 41: RubyConf Portugal 2014 - Why ruby must go!

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 }

Page 42: RubyConf Portugal 2014 - Why ruby must go!

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

Page 43: RubyConf Portugal 2014 - Why ruby must go!

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 }

Page 44: RubyConf Portugal 2014 - Why ruby must go!

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)

Page 45: RubyConf Portugal 2014 - Why ruby must go!

Ruby re-defines Object Oriented Concepts,

Go re-defines programming itself!

Page 46: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

Page 47: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

Page 48: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

Page 49: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

Page 50: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

Page 51: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessVariable declaration and assignment

Page 52: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessVariable declaration and assignment

yy

Page 53: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessVariable declaration and assignment

y := 2 // y is of type int!y = "3"

Implicit declaration

Page 54: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessVariable declaration and assignment

y := 2 // y is of type int!y = "3"

Assignment

Page 55: RubyConf Portugal 2014 - Why ruby must go!

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

Page 56: RubyConf Portugal 2014 - Why ruby must go!

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!

Page 57: RubyConf Portugal 2014 - Why ruby must go!

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!

Page 58: RubyConf Portugal 2014 - Why ruby must go!

!

Eh… what?

Page 59: RubyConf Portugal 2014 - Why ruby must go!

!

Eh… what?

https://flic.kr/p/mnZgQw

Page 60: RubyConf Portugal 2014 - Why ruby must go!

Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}

Page 61: RubyConf Portugal 2014 - Why ruby must go!

Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}

import packages

Page 62: RubyConf Portugal 2014 - Why ruby must go!

Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}

Exported function

Page 63: RubyConf Portugal 2014 - Why ruby must go!

Variable Re-declarationimport "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}

Page 64: RubyConf Portugal 2014 - Why ruby must go!

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

Page 65: RubyConf Portugal 2014 - Why ruby must go!

import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! d, err := f.Stat()!}

Programmer AwarenessVariable Re-declaration

Page 66: RubyConf Portugal 2014 - Why ruby must go!

Programmer Awareness

import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! f, err := f.Stat()!}

Variable Re-declaration

Page 67: RubyConf Portugal 2014 - Why ruby must go!

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 :=

Page 68: RubyConf Portugal 2014 - Why ruby must go!

import "os"!!func main() {!! f, err := os.Open("somefile")!! // handle error!!! f, err = f.Open("other file")!}

Programmer AwarenessVariable Re-declaration

Re-assign !explicitly.. 👍

Page 69: RubyConf Portugal 2014 - Why ruby must go!
Page 70: RubyConf Portugal 2014 - Why ruby must go!

With Great Power Comes Great Responsibility

Page 71: RubyConf Portugal 2014 - Why ruby must go!

https://flic.kr/p/kSSWb

Page 72: RubyConf Portugal 2014 - Why ruby must go!

Overloadingbut first …

Page 73: RubyConf Portugal 2014 - Why ruby must go!

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

Page 74: RubyConf Portugal 2014 - Why ruby must go!

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

Page 75: RubyConf Portugal 2014 - Why ruby must go!

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

Page 76: RubyConf Portugal 2014 - Why ruby must go!

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)

Page 77: RubyConf Portugal 2014 - Why ruby must go!

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

Page 78: RubyConf Portugal 2014 - Why ruby must go!

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)!! }!}

Page 79: RubyConf Portugal 2014 - Why ruby must go!

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!}

Page 80: RubyConf Portugal 2014 - Why ruby must go!

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)!! }!}

Page 81: RubyConf Portugal 2014 - Why ruby must go!

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!

Page 82: RubyConf Portugal 2014 - Why ruby must go!

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)!! }!}

Page 83: RubyConf Portugal 2014 - Why ruby must go!

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)!! }!}

Page 84: RubyConf Portugal 2014 - Why ruby must go!

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

Page 85: RubyConf Portugal 2014 - Why ruby must go!

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?

Page 86: RubyConf Portugal 2014 - Why ruby must go!

Include modules in order!

https://flic.kr/p/e7SnAa

Page 87: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}

Page 88: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}

Map of strings and Hotels

Page 89: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}

Easy iteration syntax!

Page 90: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!} Blank Identifier - ignore value

Page 91: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}

Page 92: RubyConf Portugal 2014 - Why ruby must go!

Programmer AwarenessIterating a Hash

hotels := make(map[string]Hotel)!!for name, _ := range hotels {!! fmt.Println(name)!}

Bad practice! !I’ll randomise the

order!

Page 93: RubyConf Portugal 2014 - Why ruby must go!

Ordered Hashes!

Page 94: RubyConf Portugal 2014 - Why ruby must go!

Ordered Hashes!

Page 95: RubyConf Portugal 2014 - Why ruby must go!

Pushing some Goodies into Ruby

https://flic.kr/p/awu6ZA

Page 96: RubyConf Portugal 2014 - Why ruby must go!

Defer

mu sync.Mutex!!func foo() {! mu.Lock()! defer mu.unLock()! // do something...!}

https://flic.kr/p/awu6ZA

Page 97: RubyConf Portugal 2014 - Why ruby must go!

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

Page 98: RubyConf Portugal 2014 - Why ruby must go!

Concurrency Parallelism

Multi-core Processing

https://flic.kr/p/awu6ZA

Page 99: RubyConf Portugal 2014 - Why ruby must go!

Example - Relay Race

• 4 legs of the race

• Each leg does processing concurrently.

• Completion should be in order. (pass the baton)

Page 100: RubyConf Portugal 2014 - Why ruby must go!

Concurrent Example

Leg 1Leg 2

Leg 3Leg 4

Page 101: RubyConf Portugal 2014 - Why ruby must go!

Concurrent Processing

Leg 1 Leg

2Leg

3 Leg 4

CPU churn - CPU time consuming operation.

Page 102: RubyConf Portugal 2014 - Why ruby must go!

Completion Order

Leg 1Leg 2

Leg 3Leg 4

Page 103: RubyConf Portugal 2014 - Why ruby must go!

Completion Order

Leg 1Leg 2

Leg 3Leg 4

Page 104: RubyConf Portugal 2014 - Why ruby must go!

Completion Order

Leg 1Leg 2

Leg 3Leg 4

Page 105: RubyConf Portugal 2014 - Why ruby must go!

Completion Order

Leg 1Leg 2

Leg 3Leg 4

Page 106: RubyConf Portugal 2014 - Why ruby must go!
Page 107: RubyConf Portugal 2014 - Why ruby must go!
Page 108: RubyConf Portugal 2014 - Why ruby must go!

CSP!Communicating Sequential

Processes

https://flic.kr/p/awu6ZAhttps://flic.kr/p/6MwYFo

Page 109: RubyConf Portugal 2014 - Why ruby must go!

CSP!Communicating Sequential

Processes

https://flic.kr/p/awu6ZA

since 1978 !!

https://flic.kr/p/6MwYFo

Page 110: RubyConf Portugal 2014 - Why ruby must go!

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 }

Page 111: RubyConf Portugal 2014 - Why ruby must go!

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() }

Page 112: RubyConf Portugal 2014 - Why ruby must go!

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()!}

Page 113: RubyConf Portugal 2014 - Why ruby must go!

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

Page 114: RubyConf Portugal 2014 - Why ruby must go!

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

Page 115: RubyConf Portugal 2014 - Why ruby must go!

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

Page 116: RubyConf Portugal 2014 - Why ruby must go!

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!

Page 117: RubyConf Portugal 2014 - Why ruby must go!

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() }

Page 118: RubyConf Portugal 2014 - Why ruby must go!

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)!}

Page 119: RubyConf Portugal 2014 - Why ruby must go!

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

Page 120: RubyConf Portugal 2014 - Why ruby must go!

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() }

Page 121: RubyConf Portugal 2014 - Why ruby must go!

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!! ! ! }!! ! }!}

Page 122: RubyConf Portugal 2014 - Why ruby must go!

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

Page 123: RubyConf Portugal 2014 - Why ruby must go!

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!! ! ! }!! ! }!}

Page 124: RubyConf Portugal 2014 - Why ruby must go!

The Big Fight

https://flic.kr/p/9AeqD2

Page 125: RubyConf Portugal 2014 - Why ruby must go!

Generics?

https://flic.kr/p/9AeqD2

ConvenientToo early still.

interface{}

Page 126: RubyConf Portugal 2014 - Why ruby must go!

Keywords!

https://flic.kr/p/9AeqD2

Nah.. no rules, rules!

You need’em bro

Page 127: RubyConf Portugal 2014 - Why ruby must go!

GIL

https://flic.kr/p/9AeqD2

😪Compiled language

FTW

Page 128: RubyConf Portugal 2014 - Why ruby must go!

Extending & Embedding

https://flic.kr/p/9AeqD2

YeahNope. !

Only Cgo

Page 129: RubyConf Portugal 2014 - Why ruby must go!

Tooling

https://flic.kr/p/9AeqD2

gem bundler

go tools

Page 130: RubyConf Portugal 2014 - Why ruby must go!
Page 131: RubyConf Portugal 2014 - Why ruby must go!

Emergency Instructions !OR !

Lecture In Aerodynamics

Page 132: RubyConf Portugal 2014 - Why ruby must go!

Emergency Instructions

Page 133: RubyConf Portugal 2014 - Why ruby must go!

Emergency Instructions

Page 134: RubyConf Portugal 2014 - Why ruby must go!
Page 135: RubyConf Portugal 2014 - Why ruby must go!

Traction Control!Fuel Efficiency!Aerodynamics!

Tyre Temperature

Page 136: RubyConf Portugal 2014 - Why ruby must go!

Traction Control!Fuel Efficiency!Aerodynamics!

Tyre Temperature

Page 137: RubyConf Portugal 2014 - Why ruby must go!

Ruby is for developers Go is for programmers“ ”

@gautamrege @joshsoftware