Created
September 17, 2011 22:09
-
-
Save timrandg/1224423 to your computer and use it in GitHub Desktop.
why do fibers do this?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#I am curious why a fiber returns the arguments when there are no more yield statements left to evaluate--see below. Why not return nil? | |
fiber = Fiber.new do |first, second| | |
Fiber.yield first + 30 | |
Fiber.yield first + 20 | |
end | |
p fiber.resume 10, 20 # => 40 | |
p fiber.resume 10, 20 # => 30 | |
p fiber.resume 10, 20 # => [10, 20] |
Starting to see it more clearly now. I made an attempt to explain how I think it works below...is it accurate? Tim
class Fiber
alias_method :pass_in, :resume
class << self
alias_method :pass_out, :yield
end
end
fiber = Fiber.new do |a,b,c|
it, is = Fiber.pass_out a#fiber_1 runs to here, returning 10. On next resume (pass_in), we start from here also.
t = Fiber.pass_out it, c #fiber_2 runs to here
#fiber_3 runs to here
end
ret_1 = fiber.pass_in(1000,2000,3000)
ret_2 = fiber.pass_in('f', 'j')
ret_3 = fiber.pass_in(1,2,3) #only returned because there was nothing left in the fiber beyond this fiber stop
p ret_1 # => 1000
p ret_2 # => ['f', 3000]
p ret_3 # => [1,2,3]
#I have a hard time ignoring the more commonly encountered 'yield' associated with blocks. Yield in the
#context of fibers trips me up. It seems to do something different here, so I renamed it pass_out.
#Likewise, I aliased 'resume' as pass_in. So, storing the new Fiber as fiber, we call fiber.pass_in
#(= fiber.resume). This is the first call of this fiber, and the arguments get set to a,b,c as you would
#expect for a block. The code continues to run to the next line. Here the variable it and is are going
#to be set. To do that we need to know what Fiber.yield (pass_out) evaluates to. However, as soon
#as we call Fiber.yield(arg), the arg gets sent out, and the focus is passed out to the caller. This
#means ret_1 now gets arg, which is a (=1000). When we go to the next line we call fiber.pass_in('f', 'j').
#Now, the Fiber.pass_out receives the incoming 'f' and 'j' argumentsa and the it variable is set to'f',
#while the 'j' variable is assigned to is. The code continues until Fiber.pass_out(it, c) is read, now the
#focus is back #outside the Fiber block and ret_2 is assigned ["f", 3000]. When the next
#fiber.pass_in(1,2,3) is read the focus goes back to the Fiber.pass_out point and the (1,2,3) args come in.
#However, this statement 1,2,3 #is the last line of code and is therefore implicitly returned and assigned
#to ret_3.
#In reading Fibers, one can imagine a marker '_' where the Fiber.yield statement is, and imagining its
# argument to get passed out. Now the _ waits at that position for a resume call. When resume is called
# the args are brougt in at the point of the _ and the code continues to the next Fiber.yield.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Because they return the return value of the blog.
Fiber.yield
returns whatever you pass to resume. So you can do this: