From: shugo@ruby-lang.org
To: ruby-core@ruby-lang.org
Subject: [ruby-core:96534] [Ruby master Feature#16461] Proc#using
Date: Sat, 28 Dec 2019 03:32:34 +0000 (UTC) [thread overview]
Message-ID: <redmine.issue-16461.20191228033234.a02f08933897ff1c@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-16461.20191228033234@ruby-lang.org
Issue #16461 has been reported by shugo (Shugo Maeda).
----------------------------------------
Feature #16461: Proc#using
https://bugs.ruby-lang.org/issues/16461
* Author: shugo (Shugo Maeda)
* Status: Open
* Priority: Normal
* Assignee:
* Target version: 2.8
----------------------------------------
## Overview
I propose Proc#using to support block-level refinements.
```ruby
module IntegerDivExt
refine Integer do
def /(other)
quo(other)
end
end
end
def instance_eval_with_integer_div_ext(obj, &block)
block.using(IntegerDivExt) # using IntegerDivExt in the block represented by the Proc object
obj.instance_eval(&block)
end
# necessary where blocks are defined (not where Proc#using is called)
using Proc::Refinements
p 1 / 2 #=> 0
instance_eval_with_integer_div_ext(1) do
p self / 2 #=> (1/2)
end
p 1 / 2 #=> 0
```
## PoC implementation
For CRuby: https://github.com/shugo/ruby/pull/2
For JRuby: https://github.com/shugo/jruby/pull/1
## Background
I proposed [Feature #12086: using: option for instance_eval etc.](https://bugs.ruby-lang.org/issues/12086) before, but it has problems:
* Thread safety: The same block can be invoked with different refinements in multiple threads, so it's hard to implement method caching.
* _exec family support: {instance,class,module}_exec cannot be supported.
* Implicit use of refinements: every blocks can be used with refinements, so there was implementation difficulty in JRuby and it has usability issue in headius's opinion.
## Solutions in this proposal
### Thread safety
Proc#using affects the block represented by the Proc object, neither the specific Proc object nor the specific block invocation.
Method calls in a block are resolved with refinements which are used by Proc#using in the block at the time.
Once all possible refinements are used in the block, there is no need to invalidate method cache anymore.
See [these tests](https://github.com/shugo/ruby/pull/2/commits/1c922614ad7d1fb43b73e195348c81da7a4546ef) to understand how it works.
Which refinements are used is depending on the order of Proc#using invocations until all Proc#using calls are finished, but eventually method calls in a block are resolved with the same refinements.
### * _exec family support
[Feature #12086](https://bugs.ruby-lang.org/issues/12086) was an extension of _eval family, so it cannot be used with _exec family, but Proc#using is independent from _eval family, and can be used with _exec family:
```ruby
def instance_exec_with_integer_div_ext(obj, *args, &block)
block.using(IntegerDivExt)
obj.instance_exec(*args, &block)
end
using Proc::Refinements
p 1 / 2 #=> 0
instance_exec_with_integer_div_ext(1, 2) do |other|
p self / other #=> (1/2)
end
p 1 / 2 #=> 0
```
### Implicit use of refinements
Proc#using can be used only if `using Proc::Refinements` is called in the scope of the block represented by the Proc object.
Otherwise, a RuntimeError is raised.
There are two reasons:
* JRuby creates a special CallSite for refinements at compile-time only when `using` is called at the scope.
* When reading programs, it may help understanding behavior. IMHO, it may be unnecessary if libraries which uses Proc#using are well documented.
`Proc::Refinements` is a dummy module, and has no actual refinements.
--
https://bugs.ruby-lang.org/
next parent reply other threads:[~2019-12-28 3:32 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <redmine.issue-16461.20191228033234@ruby-lang.org>
2019-12-28 3:32 ` shugo [this message]
2019-12-29 18:30 ` [ruby-core:96578] [Ruby master Feature#16461] Proc#using eregontp
2019-12-31 2:09 ` [ruby-core:96604] " shugo
2020-01-02 12:44 ` [ruby-core:96624] " eregontp
2020-01-07 1:39 ` [ruby-core:96697] " shugo
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.issue-16461.20191228033234.a02f08933897ff1c@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).