Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What I learned by implementing a Ruby VM in Erlang

Johnlin
December 12, 2015

What I learned by implementing a Ruby VM in Erlang

Johnlin

December 12, 2015
Tweet

More Decks by Johnlin

Other Decks in Programming

Transcript

  1. WHAT I LEARNED BY
    IMPLEMENTING A 

    RUBY VM IN ERLANG
    John Lin(Lin Yu Hsiang)
    @johnlinvc

    View full-size slide

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

    View full-size slide

  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

    View full-size slide

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

    Message Passing.

    View full-size slide

  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)

    View full-size slide

  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.

    View full-size slide

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

    View full-size slide

  8. Start 

    waiting for 

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

    View full-size slide

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

    return
    Received message,
    Translating to

    Japanese
    Object ֆᣦच Object ല෢

    View full-size slide

  10. Waiting for 

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

    View full-size slide

  11. Receive

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

    View full-size slide

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

    View full-size slide

  13. Manually

    Waiting

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

    View full-size slide

  14. Waiting

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

    View full-size slide

  15. Waiting

    for message
    Translating

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

    View full-size slide

  16. Waiting

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

    View full-size slide

  17. Receive

    message
    Waiting 

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  21. #
    @name=alice
    Process:<0.33.0>
    #
    @name=bob
    Process:<0.34.0>
    {method_result,
    <0.34.0>, 

    “͢͠͸͏·͍Ͱ͢” }
    IMPLEMENT RUBY OBJECT IN
    ERLANG

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  28. SOLUTION
    • Run each method call in a disposable process.

    View full-size slide

  29. 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}

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide