ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: yugui@yugui.jp
To: ruby-core@ruby-lang.org
Subject: [ruby-core:82870] [Ruby trunk Feature#10344] [PATCH] Implement Fiber#raise
Date: Tue, 19 Sep 2017 09:07:07 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-66770.20170919090706.b43fb8f16bf4d6ca@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-10344.20141009002911@ruby-lang.org

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/

  parent reply	other threads:[~2017-09-19  9:07 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <redmine.issue-10344.20141009002911@ruby-lang.org>
2014-10-09  0:29 ` [ruby-core:65537] [ruby-trunk - Feature #10344] [Open] [PATCH] Implement Fiber#raise Knut.Franke
2014-10-09  2:58 ` [ruby-core:65540] [ruby-trunk - Feature #10344] " ko1
2014-10-09 10:16 ` [ruby-core:65558] " funny.falcon
2014-10-11 16:28 ` [ruby-core:65618] " Knut.Franke
2014-10-16  4:36   ` [ruby-core:65747] " SASADA Koichi
2014-10-16  4:41 ` [ruby-core:65748] " ko1
2014-10-18 11:59   ` [ruby-core:65780] " Юрий Соколов
2014-10-18 12:11 ` [ruby-core:65781] " funny.falcon
2014-10-18 13:55 ` [ruby-core:65782] " Knut.Franke
2014-10-23  1:05 ` [ruby-core:65862] " ko1
2014-10-23  1:08 ` [ruby-core:65863] " ko1
2014-10-24 16:16 ` [ruby-core:65892] " Knut.Franke
2017-09-19  9:07 ` yugui [this message]
2018-12-12  1:51 ` [ruby-core:90431] [Ruby trunk Feature#10344] " samuel
2018-12-12  1:52 ` [ruby-core:90432] " samuel
2018-12-20  1:11 ` [ruby-core:90626] [Ruby trunk Feature#10344][Assigned] " samuel
2018-12-28 13:04 ` [ruby-core:90773] [Ruby trunk Feature#10344] " samuel
2018-12-30 15:48 ` [ruby-core:90826] " naruse
2018-12-30 17:44 ` [ruby-core:90827] " ko1
2018-12-30 21:56 ` [ruby-core:90831] " samuel
2018-12-31  5:00 ` [ruby-core:90834] " naruse
2019-05-28 11:26 ` [ruby-core:92875] " fg
2019-09-14 21:49 ` [ruby-core:94938] [Ruby master " samuel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-66770.20170919090706.b43fb8f16bf4d6ca@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).