Issue #17331 has been updated by nevans (Nicholas Evans).


Thanks for taking a look.

ko1 (Koichi Sasada) wrote in #note-7:
> Sorry, could you explain the motivation and specification?
> It seems there are many discussion on GH and other tickets, quoting them is great if already well described.

Motivation: ruby 2.7 `Fiber#raise` only works with yielding fibers (although this limitation isn't documented). `Fiber#raise` should be usable with transferring fibers as well.

So, with ruby 2.7:
```
ruby -rfiber -e 'puts RUBY_VERSION; root = Fiber.current; f1 = Fiber.new { (1..).each do |i| root.transfer(i) end }; 3.times { puts f1.transfer }; p((f1.raise("error now") rescue $!))'
2.7.2
1
2
3
#<FiberError: cannot resume transferred Fiber>
```

With this patch:
```
tool/runruby.rb -rfiber -e 'puts RUBY_VERSION; root = Fiber.current; f1 = Fiber.new { (1..).each do |i| root.transfer(i) end }; 3.times { puts f1.transfer }; p((f1.raise("error now") rescue $!))'
3.0.0
1
2
3
#<RuntimeError: error now>
```
> In general, exception on the transferred fibers will return to root fibers. Do you expect it?

Yes. Because transferred fibers always return to root, calling `Fiber#raise` should be coordinated with or called by a scheduler.

> I'm not sure what is implicit approach and what is explicit approach. Could you summarize the spec?

Because transferring fibers might not return control back to the current fiber and might require coordination with a scheduler, I thought it would be safest to require a `transfer: true` keyword arg when using it with transferring fibers. But Samuel convinced me that the implicit version is fine.

----------------------------------------
Feature #17331: Let Fiber#raise work with transferring fibers
https://bugs.ruby-lang.org/issues/17331#change-88783

* Author: nevans (Nicholas Evans)
* Status: Open
* Priority: Normal
----------------------------------------
It would be useful to use `raise` on transferring fibers just as we can with yielding fibers.

I've added a `transfer` kwarg, so it is not automatic; the caller must know how to handle the fiber.  If you call a yielding fiber with `transfer: true` or a transferring fiber without `transfer: true`, a `FiberError` will be raised. Resuming fibers still raise a `FiberError`.

```ruby
yielding_fiber.raise "message"
# => resumes and raises from the last Fiber.yield

transferring_fiber.raise "message", transfer: true
# => transfers and raises from the last fiber.transfer

resuming_fiber.raise "message"
# => raises FiberError
```

Implementation: https://github.com/ruby/ruby/pull/3783


I also implemented a second version that implicitly and automatically selects `rb_fiber_transfer_kw` for transferring fibers and `rb_fiber_resume_kw` for yielding fibers. The implicit version also raises `FiberError` on resuming fibers.


```ruby
yielding_fiber.raise "message"
# => resumes and raises from the last Fiber.yield

transferring_fiber.raise "message"
# => transfers and raises from the last fiber.transfer

resuming_fiber.raise "message"
# => raises FiberError
```

Alternate implicit implementation: https://github.com/ruby/ruby/pull/3795

I slightly prefer the explicit version, but I'm okay with the implicit version.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>