What I learned by implementing a Ruby VM in Erlang

3f7d9611fc919c98512b779cde637dfc?s=47 Johnlin
December 12, 2015

What I learned by implementing a Ruby VM in Erlang

3f7d9611fc919c98512b779cde637dfc?s=128

Johnlin

December 12, 2015
Tweet

Transcript

  1. 1.

    WHAT I LEARNED BY IMPLEMENTING A 
 RUBY VM IN

    ERLANG John Lin(Lin Yu Hsiang) @johnlinvc
  2. 2.

    ABOUT ME • Me: John Lin (Yu Hsiang Lin) from

    Taiwan • @johnlinvc • Work at Spoonrocket.
  3. 3.

    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
  4. 4.

    WHY ERLANG? • Erlang is a functional programming language designed

    for concurrency. • Famous for Lightweight Process and the 
 Message Passing.
  5. 5.

    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)
  6. 6.

    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.
  7. 7.
  8. 8.

    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 ല෢
  9. 9.

    Start 
 waiting for 
 return how_is_sushi Idle Object ֆᣦच

    Object ല෢ class Alice def chat_with_bob response = bob.how_is_sushi? end end
  10. 10.

    class Bob def how_is_sushi? "͢͠Θ͏·͍Ͱ͢" end end Waiting for 


    return Received message, Translating to
 Japanese Object ֆᣦच Object ല෢
  11. 11.

    Waiting for 
 return ͢͠Θ͏·͍Ͱ͢ Sending message Object ֆᣦच Object

    ല෢ class Bob def how_is_sushi? "͢͠Θ͏·͍Ͱ͢" end end
  12. 12.

    Receive
 response Idle Object ֆᣦच Object ല෢ class Alice def

    chat_with_bob response = bob.how_is_sushi? end end
  13. 13.
  14. 14.

    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 ല෢
  15. 15.

    Manually
 Waiting
 for message Received message Process ֆᣦच Process ֆᣦच

    Process ല෢ chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end.
  16. 16.

    Waiting
 for message Received message bob_loop(State) -> receive {Sender, ‘how_is_sushi?’}

    -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State). Process ֆᣦच Process ല෢
  17. 17.

    Waiting
 for message Translating
 to Japanese Process ֆᣦच Process ല෢

    bob_loop(State) -> receive {Sender, ‘how_is_sushi?’} -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State).
  18. 18.

    Waiting
 for message Sending message {ok,”͢͠Θ͏·͍Ͱ͢”} Process ֆᣦच Process ല෢

    bob_loop(State) -> receive {Sender, ‘how_is_sushi?’} -> Sender ! {ok, "͢͠Θ͏·͍Ͱ͢"} end, bob_loop(State).
  19. 19.

    Receive
 message Waiting 
 for message Process ֆᣦच Process ല෢

    chat_with_bob(Bob) -> Bob ! {self(), ‘how_is_sushi?’}, receive {ok, Message} -> Message end.
  20. 20.

    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
  21. 24.
  22. 25.

    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
  23. 26.

    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.
  24. 27.

    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 ല෢
  25. 28.

    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).
  26. 29.

    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).
  27. 30.

    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).
  28. 32.

    RUBY METHOD IN ERLANG #<Alice:0x..> @name=alice Process:<0.33.0> spawn new process


    for bob.how_is_sushi? Process:<0.35.0> {receiver, method,
 arg, env, sender}
  29. 33.

    RUBY METHOD IN ERLANG #<Alice:0x..> @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
  30. 34.

    ERRUBY CURRENT STATUS • github.com/johnlinvc/erruby • Current Status: define class,

    evaluate method with block, local var. • Current Goal: able to run RubySpec
  31. 35.

    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
  32. 36.

    • 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.
  33. 37.

    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.
  34. 38.

    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.
  35. 39.

    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
  36. 40.

    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.