ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:93337] [Ruby trunk Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
@ 2019-06-24 17:49 ` nelhage
  2019-06-28 10:25 ` [ruby-core:93405] " eregontp
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: nelhage @ 2019-06-24 17:49 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been reported by nelhage (Nelson Elhage).

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:93405] [Ruby trunk Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
  2019-06-24 17:49 ` [ruby-core:93337] [Ruby trunk Feature#15955] UnboundMethod#apply nelhage
@ 2019-06-28 10:25 ` eregontp
  2019-07-25 21:01 ` [ruby-core:93916] [Ruby master " nelhage
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: eregontp @ 2019-06-28 10:25 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by Eregon (Benoit Daloze).


Escape analysis might be able to remove the Method allocation of `unbound.bind(recv).call(*args)`.
In fact, TruffleRuby does it for such a pattern.

So the interesting question for me is whether this should be fixed by the JIT or by a new method.

Could you share a benchmark representing your usage?

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-78947

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:93916] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
  2019-06-24 17:49 ` [ruby-core:93337] [Ruby trunk Feature#15955] UnboundMethod#apply nelhage
  2019-06-28 10:25 ` [ruby-core:93405] " eregontp
@ 2019-07-25 21:01 ` nelhage
  2019-07-26 13:48 ` [ruby-core:93933] " jean.boussier
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: nelhage @ 2019-07-25 21:01 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by nelhage (Nelson Elhage).


Whoops, sorry for the belated response -- Redmine email seems to not be working for me. We have a `replace_method` helper that is a shorthand for doing something like:

```
orig_require = Kernel.instance_method(:require)
Kernel.define_method(:require) do |*args|
  # … do some pre-processing
  orig_require.bind(self).call(*args)
end
```

We use it in a number of places, including to replace `require` as part of our custom autoloader (c.f. this talk: https://www.youtube.com/watch?v=lKMOETQAdzs)

I'm not quite sure how to get a representative microbenchmark; I am sure I could construct ones where the overhead is anywhere from ~0% to arbitrarily high. Profiling shows that as much as ~6% of the allocation on app startup comes from `UnboundMethod#bind` calls.

There are also other places I'd like to use this idiom. We had an incident the other day related to Sorbet's [use of `is_a?`](https://github.com/sorbet/sorbet/blob/d12b7144d2222398e0f28a772b7759fe26b2b9ba/gems/sorbet-runtime/lib/types/types/simple.rb#L20) (a `BasicObject` subtype that was being passed around had a surprising `is_a?` implementation) in runtime checking. 

I'd love to be able to grab `Object.instance_method(:is_a?)` and then use that in our typechecking to make sure that we can test true subtyping no matter what monkey-patches are in place, but we know from past work that adding even a single allocation to the common case of runtime typechecking is too expensive.

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80042

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:93933] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2019-07-25 21:01 ` [ruby-core:93916] [Ruby master " nelhage
@ 2019-07-26 13:48 ` jean.boussier
  2019-07-26 18:47 ` [ruby-core:93936] " eregontp
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: jean.boussier @ 2019-07-26 13:48 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by byroot (Jean Boussier).


Zeitwerk had the exact same use case recently: https://github.com/fxn/zeitwerk/blob/ba7ff65d40a4309701981f9443249ac7e0e8c65f/lib/zeitwerk/real_mod_name.rb 

i.e. get the true Module name even if the method was redefined.

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80062

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:93936] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2019-07-26 13:48 ` [ruby-core:93933] " jean.boussier
@ 2019-07-26 18:47 ` eregontp
  2019-07-30  8:13 ` [ruby-core:94040] " ko1
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: eregontp @ 2019-07-26 18:47 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by Eregon (Benoit Daloze).


I think this makes sense for convenience and better performance on MRI or during interpretation (vs in compiled code).

Using an UnboundMethod for getting a copy of a method at a given time is indeed a good usage, we use it in TruffleRuby quite a bit.

For the specific case of `is_a?`, may I recommend using `Module#===`?
That's much less often overridden, and it works for BasicObject (#is_a? is only defined in Kernel, so not for BasicObject).

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80098

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:94040] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2019-07-26 18:47 ` [ruby-core:93936] " eregontp
@ 2019-07-30  8:13 ` ko1
  2019-08-13 21:27 ` [ruby-core:94329] " ruby-lang-bugs
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: ko1 @ 2019-07-30  8:13 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by ko1 (Koichi Sasada).


> In fact, TruffleRuby does it for such a pattern.

I wonder that people use this pattern! (I'd never used it except test).

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80265

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:94329] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2019-07-30  8:13 ` [ruby-core:94040] " ko1
@ 2019-08-13 21:27 ` ruby-lang-bugs
  2019-08-23  2:40 ` [ruby-core:94493] " mame
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: ruby-lang-bugs @ 2019-08-13 21:27 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by darkdimius (Dmitry Petrashko).


> I wonder that people use this pattern! (I'd never used it except test).

This pattern currently represents substantial fraction of allocations that Sorbet runtime does, so building a way to not allocate in this pattern might have a sizeable impact in reducing the overhead of runtime type checking.

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80717

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:94493] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2019-08-13 21:27 ` [ruby-core:94329] " ruby-lang-bugs
@ 2019-08-23  2:40 ` mame
  2019-08-23  3:28 ` [ruby-core:94495] " mame
  2019-08-30  0:05 ` [ruby-core:94673] " mame
  9 siblings, 0 replies; 10+ messages in thread
From: mame @ 2019-08-23  2:40 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by mame (Yusuke Endoh).

File umethod_apply.patch added

Hi @nelhage and @darkdimius :-)

I'm attaching a patch for `UnboundMethod#apply(obj, *args, &blk)` as a shortcut to `.bind(obj).call(*args, &blk)` without allocation of a Method object.

I have heard the same situation as Sorbet for `pp`.  `pp` calls `method` method against its arguments.  The intention is to call `Object#method`, but sometimes it is overridden with completely different behavior, e.g., `Net::HTTPGenericRequest#method`.  So `pp` is using the same hack: https://github.com/ruby/ruby/blob/master/lib/pp.rb#L92

So I agree with the proposal.  I'm unsure if the name `apply` is good or not.  I'd like to ask matz at the next dev-meeting.

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80928

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`



---Files--------------------------------
umethod_apply.patch (5.01 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:94495] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (7 preceding siblings ...)
  2019-08-23  2:40 ` [ruby-core:94493] " mame
@ 2019-08-23  3:28 ` mame
  2019-08-30  0:05 ` [ruby-core:94673] " mame
  9 siblings, 0 replies; 10+ messages in thread
From: mame @ 2019-08-23  3:28 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by mame (Yusuke Endoh).


Here is a benchmark:

```
class Foo
  def foo
  end
end
meth = Foo.instance_method(:foo)
obj = Foo.new

10000000.times { meth.bind(obj).call } # 1.84 sec
10000000.times { meth.apply(obj)     } # 1.04 sec
```

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-80930

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`



---Files--------------------------------
umethod_apply.patch (5.01 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:94673] [Ruby master Feature#15955] UnboundMethod#apply
       [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
                   ` (8 preceding siblings ...)
  2019-08-23  3:28 ` [ruby-core:94495] " mame
@ 2019-08-30  0:05 ` mame
  9 siblings, 0 replies; 10+ messages in thread
From: mame @ 2019-08-30  0:05 UTC (permalink / raw)
  To: ruby-core

Issue #15955 has been updated by mame (Yusuke Endoh).


Matz approved the feature.  The name "apply" was arguable in some terms:

* We may want to use the name "apply" for other purpose in future.
* This API will be used not so frequently.  Only some fundamental libraries (like pp, sorbet-runtime, zeitwerk, etc.) will use it.

I proposed `UnboundMethod#bind_call` at the developers' meeting, and matz liked it.  I'll commit it soon.

----------------------------------------
Feature #15955: UnboundMethod#apply
https://bugs.ruby-lang.org/issues/15955#change-81278

* Author: nelhage (Nelson Elhage)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I'd love a way to apply an UnboundMethod to a receiver and list of args without having to first `bind` it. I've ended up using `UnboundMethod`s in some hot paths in my application due to our metaprogramming idioms, and the allocation from `.bind` is comparatively expensive.

I'd love `unbound_method.apply(obj, args…)` to be equivalent to `unbound_method.bind(obj).call(args…)` but without allocating the intermediate `Method`



---Files--------------------------------
umethod_apply.patch (5.01 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-08-30  0:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-15955.20190624174954@ruby-lang.org>
2019-06-24 17:49 ` [ruby-core:93337] [Ruby trunk Feature#15955] UnboundMethod#apply nelhage
2019-06-28 10:25 ` [ruby-core:93405] " eregontp
2019-07-25 21:01 ` [ruby-core:93916] [Ruby master " nelhage
2019-07-26 13:48 ` [ruby-core:93933] " jean.boussier
2019-07-26 18:47 ` [ruby-core:93936] " eregontp
2019-07-30  8:13 ` [ruby-core:94040] " ko1
2019-08-13 21:27 ` [ruby-core:94329] " ruby-lang-bugs
2019-08-23  2:40 ` [ruby-core:94493] " mame
2019-08-23  3:28 ` [ruby-core:94495] " mame
2019-08-30  0:05 ` [ruby-core:94673] " mame

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).