[ruby-core:105870] [Ruby master Feature#18276] `Proc#bind_call(obj)` same as `obj.instance_exec(..., &proc_obj)`
From:
"Eregon (Benoit Daloze)" <noreply@...>
Date:
2021-10-29 20:24:13 UTC
List:
ruby-core #105870
Issue #18276 has been updated by Eregon (Benoit Daloze).
jhawthorn (John Hawthorn) wrote in #note-2:
> In Rails we use `obj.instance_exec(&proc_obj)` in a few places. One of the downsides `instance_exec` has is that it creates a singleton class for `obj`, which isn't friendly to method caches or JITs. `Proc#bind_call` would be very useful to us if it behaved similarly but did not create a singleton class.
I think `instance_exec` doesn't create a singleton class, only if needed by e.g. `Object.new.instance_exec { def foo; end }` (at least on TruffleRuby, maybe it depends how eagerly the cref is computed by the Ruby implementation).
I think the same applies to `Proc#bind_call` (`-> { def foo; end }.bind_call(Object.new)`).
I'm not against such a method, but IMHO this alone is not solving #18243 in a reasonable way.
If an object is made shareable, every object reachable from it should be frozen or shareable, and magically ignoring the Proc's `self` is conceptually ugly and I believe very confusing for many.
Maybe `Ractor.make_shareable(someProc)` should return a Proc with a special receiver (e.g., Qundef), which simply can't be called via `.call` on any Ractor and can only be called via `Proc#bind_call`.
Then at least that shareable Proc wouldn't refer to any unshared object (which would violate the docs and expected semantics of `Ractor.make_shareable`)
----------------------------------------
Feature #18276: `Proc#bind_call(obj)` same as `obj.instance_exec(..., &proc_obj)`
https://bugs.ruby-lang.org/issues/18276#change-94408
* Author: ko1 (Koichi Sasada)
* Status: Open
* Priority: Normal
----------------------------------------
`Proc#bind_call(obj)` same as `obj.instance_exec(..., &proc_obj)`
```ruby
proc_obj = proc{|params...| ...}
obj.instance_exec(params..., &proc_obj)
```
is frequent pattern.
```
$ gem-codesearch 'instance_exec.+\&' | wc -l
9558
```
How about to introduce new method `Proc#bind_call`?
```ruby
class Proc
def bind_call obj, *args
obj.instance_exec(*args, &self)
end
end
pr = ->{ p self }
pr.bind_call("hello") #=> "hello"
pr.bind_call(nil) #=> nil
```
It is similar to `UnboundMethod#bind_call`.
----
My motivation;
I want to solve shareable Proc's issue https://bugs.ruby-lang.org/issues/18243 and one idea is to prohibit `Proc#call` for shareable Proc's, but allow `obj.instance_exec(&pr)`. To make shortcut, I want to introduce `Proc#bind_call`.
`UnboundProc` is another idea, but I'm not sure it is good idea...
Anyway, we found that there are many usage of `instance_exec(&proc_obj)`, so `Proc#bind_call` is useful not for Ractors.
--
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>