Slide 1

Slide 1 text

WHAT I LEARNED BY IMPLEMENTING A 
 RUBY VM IN ERLANG John Lin(Lin Yu Hsiang) @johnlinvc

Slide 2

Slide 2 text

ABOUT ME • Me: John Lin (Yu Hsiang Lin) from Taiwan • @johnlinvc • Work at Spoonrocket.

Slide 3

Slide 3 text

YET ANOTHER RUBY VM? • Concurrency is an important feature for
 future Ruby. • I want to try Ruby in the concurrent world. • ErRuby: github.com/johnlinvc/erruby

Slide 4

Slide 4 text

WHY ERLANG? • Erlang is a functional programming language designed for concurrency. • Famous for Lightweight Process and the 
 Message Passing.

Slide 5

Slide 5 text

LIGHTWEIGHT PROCESS • Erlang processes are NOT system processes or threads. • Processes share nothing with each other. • Erlang can support millions of processes running at the same time. • Feels like Ruby objects (well defined)

Slide 6

Slide 6 text

MESSAGE PASSING • Processes communicate with others only by sending and receiving messages. • Processes make decisions based on the messages received. • Just like real life humans talking to each others.

Slide 7

Slide 7 text

EXAMPLE

Slide 8

Slide 8 text

class Alice def chat_with_bob response = bob.how_is_sushi? end end Invoke 
 how_is_sushi
 on Bob how_is_sushi Idle Object ֆᣦच Object ല෢

Slide 9

Slide 9 text

Start 
 waiting for 
 return how_is_sushi Idle Object ֆᣦच Object ല෢ class Alice def chat_with_bob response = bob.how_is_sushi? end end

Slide 10

Slide 10 text

class Bob def how_is_sushi? "͢͠Θ͏·͍Ͱ͢" end end Waiting for 
 return Received message, Translating to
 Japanese Object ֆᣦच Object ല෢

Slide 11

Slide 11 text

Waiting for 
 return ͢͠Θ͏·͍Ͱ͢ Sending message Object ֆᣦच Object ല෢ class Bob def how_is_sushi? "͢͠Θ͏·͍Ͱ͢" end end

Slide 12

Slide 12 text

Receive
 response Idle Object ֆᣦच Object ല෢ class Alice def chat_with_bob response = bob.how_is_sushi? end end

Slide 13

Slide 13 text

EXAMPLE

Slide 14

Slide 14 text

chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end. Sending
 message {Alice, ‘do you like the sushi?’} Waiting 
 for message Process ֆᣦच Process ല෢

Slide 15

Slide 15 text

Manually
 Waiting
 for message Received message Process ֆᣦच Process ֆᣦच Process ല෢ chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end.

Slide 16

Slide 16 text

Waiting
 for message Received message bob_loop(State) -> receive {Sender, ‘how_is_sushi?’} -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State). Process ֆᣦच Process ല෢

Slide 17

Slide 17 text

Waiting
 for message Translating
 to Japanese Process ֆᣦच Process ല෢ bob_loop(State) -> receive {Sender, ‘how_is_sushi?’} -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State).

Slide 18

Slide 18 text

Waiting
 for message Sending message {ok,”͢͠Θ͏·͍Ͱ͢”} Process ֆᣦच Process ല෢ bob_loop(State) -> receive {Sender, ‘how_is_sushi?’} -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State).

Slide 19

Slide 19 text

Receive
 message Waiting 
 for message Process ֆᣦच Process ല෢ chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end.

Slide 20

Slide 20 text

ERLANG PROCESS VS 
 RUBY OBJECTS Erlang Process Ruby Object cost Cheap, 
 maximum is 134,217,727 Cheap,
 everything is an object How to communicate with each others? Asynchronous
 message passing Synchronous
 messaging passing

Slide 21

Slide 21 text

IMPLEMENT RUBY OBJECT IN ERLANG # @name=alice Process:<0.33.0> # @name=bob Process:<0.34.0>

Slide 22

Slide 22 text

# @name=alice Process:<0.33.0> # @name=bob Process:<0.34.0> {send, <0.33.0>, ‘how_is_sushi’, [] } IMPLEMENT RUBY OBJECT IN ERLANG

Slide 23

Slide 23 text

# @name=alice Process:<0.33.0> # @name=bob Process:<0.34.0> {method_result, <0.34.0>, 
 “͢͠͸͏·͍Ͱ͢” } IMPLEMENT RUBY OBJECT IN ERLANG

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

TALKING TO YOURSELF • The problem is we often call methods on self def is_sushi_good? sushi_score > 90 end def sushi_score 9001 end

Slide 26

Slide 26 text

Sending
 message {Alice, ‘how_is_sushi?’} Waiting 
 for message Process ല෢ Process ֆᣦच chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end.

Slide 27

Slide 27 text

Received
 message bob_loop(State) -> receive {Sender, 'how_is_sushi?'} -> (self() ! {self(), sushi_score}), receive {ok, Score} -> Sender ! {ok,Score > 90} end; {Sender, sushi_score} -> Sender ! {ok, 9000} end, bob_loop(State). Process ല෢

Slide 28

Slide 28 text

Send message
 to self() {Bob, sushi_score} Process ല෢ bob_loop(State) -> receive {Sender, 'how_is_sushi?'} -> (self() ! {self(), sushi_score}), receive {ok, Score} -> Sender ! {ok,Score > 90} end; {Sender, sushi_score} -> Sender ! {ok, 9000} end, bob_loop(State).

Slide 29

Slide 29 text

Waiting 
 for message
 from Bob Process ല෢ bob_loop(State) -> receive {Sender, 'how_is_sushi?'} -> (self() ! {self(), sushi_score}), receive {ok, Score} -> Sender ! {ok,Score > 90} end; {Sender, sushi_score} -> Sender ! {ok, 9000} end, bob_loop(State).

Slide 30

Slide 30 text

Waiting
 Forever …… Process ല෢ bob_loop(State) -> receive {Sender, 'how_is_sushi?'} -> (self() ! {self(), sushi_score}), receive {ok, Score} -> Sender ! {ok,Score > 90} end; {Sender, sushi_score} -> Sender ! {ok, 9000} end, bob_loop(State).

Slide 31

Slide 31 text

SOLUTION • Run each method call in a disposable process.

Slide 32

Slide 32 text

RUBY METHOD IN ERLANG # @name=alice Process:<0.33.0> spawn new process
 for bob.how_is_sushi? Process:<0.35.0> {receiver, method,
 arg, env, sender}

Slide 33

Slide 33 text

RUBY METHOD IN ERLANG # @name=alice Process:<0.33.0> spawn new process
 for bob.how_is_sushi? Process:<0.35.0> {receiver, method,
 arg, env, sender} Process:<0.36.0> {receiver, method,
 arg, env, sender} spawn new process
 for bob.sushi_score

Slide 34

Slide 34 text

ERRUBY CURRENT STATUS • github.com/johnlinvc/erruby • Current Status: define class, evaluate method with block, local var. • Current Goal: able to run RubySpec

Slide 35

Slide 35 text

RUBY METHOD CALL • TODO use graph • alice: invoke method how_is_sushi on bob. • alice waiting the method to return. • bob returns “Sushi wa umai desu" . • alice gets the result

Slide 36

Slide 36 text

• TODO use graphs • Bob is waiting Alice to talk. • Alice: Do you like the sushi today? • Alice starts waiting Bob’s response • Bob receives the message, starts thinking how to respond in Japanese. • Bob: Sushi wa umai desu. • Alice receives the message, starts thinking what to say next.

Slide 37

Slide 37 text

Invoke 
 how_is_sushi
 on Bob Send how_is_sushi to bob Action Idle chat_with_bob(Bob) -> Bob ! {self(), 'do you like the sushi?'}, receive {ok, Message} -> Message end.

Slide 38

Slide 38 text

Invoke 
 how_is_sushi
 on Bob Send how_is_sushi to bob Action Idle chat_with_bob(Bob) -> Bob ! {self(), 'do you like the sushi?'}, receive {ok, Message} -> Message end.

Slide 39

Slide 39 text

THE PROBLEM • In Ruby, we invoke method without explicit receiver, which will set self as default receiver • For example: 
 puts “hello world” 
 is invoking puts on self with argument 
 “hello world”, without typing self

Slide 40

Slide 40 text

CAN’T TALK TO YOURSELF WHILE CHATING • TODO use graph • Bob waits for Alice to Talk. • Alice ask Bob: is_sushi_good? • In Bob receive block, receive the message, send message “sushi_score” to self(Bob), then waiting Bob to respond. • Bob can’t receive the “sushi_score” message because he’s already in a receive block, Bob waits forever, program hanged.