rubyconf portugal 2014 - why ruby must go!

Post on 18-Nov-2014

2.878 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

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

top related