[#82706] [Ruby trunk Bug#13851] getting "can't modify string; temporarily locked" on non-frozen instances — cardoso_tiago@...
Issue #13851 has been updated by chucke (Tiago Cardoso).
3 messages
2017/09/07
[#82853] [Ruby trunk Bug#13916] Race condition when sending a signal to a new fork — russell.davis@...
Issue #13916 has been reported by russelldavis (Russell Davis).
3 messages
2017/09/19
[#82892] [Ruby trunk Bug#13921] buffered read_nonblock doesn't work as expected using SSLSocket — cardoso_tiago@...
Issue #13921 has been updated by chucke (Tiago Cardoso).
3 messages
2017/09/20
[ruby-core:82870] [Ruby trunk Feature#10344] [PATCH] Implement Fiber#raise
From:
yugui@...
Date:
2017-09-19 09:07:07 UTC
List:
ruby-core #82870
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: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>