From: yugui@... Date: 2017-09-19T09:07:07+00:00 Subject: [ruby-core:82870] [Ruby trunk Feature#10344] [PATCH] Implement Fiber#raise Issue #10344 has been updated by yugui (Yuki Sonoda). Assignee set to ko1 (Koichi Sasada) Target version set to 2.5 Let me add another use case which I discussed with naruse and akr in RubyKaigi. `Fiber#raise` is helpful to improve compatibility of methods with blocks (internal iterators) and `Enumerator` (external iterators). This happened for me when I tried to write an adapter between two independently-developed APIs. Here's a simplified example below. You can also find the real example in https://github.com/supership-jp/activerecord-spanner-adapter/blob/master/lib/active_record/connection_adapters/spanner/client.rb. # Example Suppose that we have a third-paty API, which we cannot control. ``` def with_transaction tx = Transaction.new begin yield tx rescue tx.rollback else tx.commit end end ``` And now I need to begin a transaction in a method and then need to commit or rollback the transaction in other methods. ``` class TransactionManager def begin_transaction @iter = Transaction.enum_for(:begin_transaction) @tx = @iter.next # skip error handlings for simplicity end def commit_transaction loop { @iter.next } ensure @tx = nil end def abort_transaction(reason = RuntimeError.new) # ??? How can I let the iterator know the error raised @iter.raise(reason) end attr_reader :tx end ``` In other words, internal iterators in Ruby can manage resources in it but external iterators can't even if the user tried to take responsibility of calling cleanup mechanism. In the real usecase, `with_transaction` was an API given by `google-cloud-spanner` gem and the interface of the `TransactionManager` was the one I had to implement for ActiveRecord. # Proposal Although I could certainly implement the adapter without the native `Fiber#raise`, it would be still helpful if internal iterators and external iterators in Ruby were more consistent. Can we have `Fiber#raise` and `Enumerator#raise` on top of it to improve the consistency? ko1? FYI: I've confirmed that the patch by nome still works fine for ruby-trunk. https://github.com/yugui/ruby/commit/5a04a8b49b5086686fd75c6635c95c12ccc6caa8 ---------------------------------------- Feature #10344: [PATCH] Implement Fiber#raise https://bugs.ruby-lang.org/issues/10344#change-66770 * Author: nome (Knut Franke) * Status: Open * Priority: Normal * Assignee: ko1 (Koichi Sasada) * Target version: 2.5 ---------------------------------------- While it is possible to implement this in pure Ruby (by wrapping Fiber.yield and Fiber#resume), this feels like a low-level feature that ought to be provided out of the box. Also, the C implementation is more straight-forward, and more efficient. Unfortunately, it is not quite possible to implement this as a C extension module (without resorting to wrappers again); cf. the change to make_passing_arg(). Example usage: ~~~ fib = Fiber.new do counter = 0 loop { counter += Fiber.yield } counter end fib.resume fib.resume 10 fib.resume 100 fib.raise StopIteration # => 110 ~~~ ---Files-------------------------------- 0001-Implement-Fiber-raise.patch (4.12 KB) 0001-Implement-Fiber-raise.patch (3.51 KB) 0001-Implement-Fiber-raise-in-ext-fiber.patch (3.6 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: