Skip to content

Instantly share code, notes, and snippets.

@timrandg
Created September 17, 2011 22:09
Show Gist options
  • Select an option

  • Save timrandg/1224423 to your computer and use it in GitHub Desktop.

Select an option

Save timrandg/1224423 to your computer and use it in GitHub Desktop.
why do fibers do this?
#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]
@rkh

rkh commented Sep 17, 2011

Copy link
Copy Markdown

Because they return the return value of the blog. Fiber.yield returns whatever you pass to resume. So you can do this:

fiber = Fiber.new do
  puts Fiber.yield
  "done"
end

fiber.resume
puts fiber.resume("ready?")

@timrandg

Copy link
Copy Markdown
Author

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