Question

I'm trying to use Ruby's Fibers to create a REPL, with one Fiber acting as the frontend - taking input and displaying output - and one Fiber as backend - processing input from the frontend and returning output for display.

(I'm doing this partly because I vaguely need a REPL, partly because I wanted to understand Fibers, and partly because I figured this would allow testing - simply replace the frontend in the test framework to test the backend, and vice-versa).

Trouble is, I can't find any good documentation on how to actually use the full Fibers library, and my initial guess doesn't work. So, I have four questions:

  1. Is this a halfway-sensible idea? Am I going to run into huge trouble trying to make a REPL from Fibers?
  2. I don't think I can do this without the Fibers library, since I need to pass values both ways. Is that right?
  3. Can anyone point me at decent, start-at-the-beginning tutorials or documentation on Ruby Fibers (as in the library, not the unidirectional generators stuff)?
  4. Why doesn't the following work? It correctly displays Enter a string:, and repeatedly accepts input; but every time I supply a line of input, it just displays the first line of input reversed (sample output is included, in case that wasn't clear).

Code:

require 'fiber'


# Simple REPL. Echo back the user's input, reversed, until they
# enter "pots" (resulting in "stop")
frontend = Fiber.new do |backend, output|
  while output != 'stop' do
    puts output
    print ": "
    input = gets
    output = backend.transfer(frontend, input)
  end
end

backend = Fiber.new do |frontend, input|
  loop do
    frontend.transfer(input.reverse)
  end
end

frontend.transfer(backend, "Enter a string:")

Output:

Enter a string:
: Hello

olleH
: World

olleH
:
Était-ce utile?

La solution

Answers, in order:

  1. Fibers are wrong for this. Fibers are a very high level feature meant for cooperative concurrency. Using them for a simple use case covered by functions and blocks doesn't make sense.
  2. No. Look at your REPL, written using only methods:

    def repl(output, &backend)
      input = nil
      while output != "stop"
        puts output
        print ': '
        input = gets.chomp
        output = backend.call(input)
      end
    end
    repl("Enter a string: ") {|input| input.reverse}
    

    Which outputs:

    Enter a string:                                                                                                                      
    : Hi                                                                                                                                 
    iH                                                                                                                                   
    : Hello                                                                                                                              
    olleH
    : Bork
    kroB
    

    Works perfectly.

  3. Ruby's own documentation: http://ruby-doc.org/core-2.0.0/Fiber.html

  4. When you call transfer or resume multiple times, the arguments are only passed to the block of the fiber the first time. So each time you call transfer the backed fiber is still reversing the first string it was passed, because it never got another. That's why fibers are wrong for implementing this.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top