Why does UnboundMethod need to remember the class it was retrieved from (not merely owner)?

class Base; def foo; end end
class Sub < Base; end

base_foo = Base.instance_method :foo
sub_foo = Sub.instance_method :foo
sub_foo.bind(Base.new).call


conceptually both base_foo and sub_foo refer to the same method (foo
with owner Base)
but they are not equal (==, eql?) and sub_foo can’t be bound to an
instance of Base.

Why is it significant that that sub_foo was retrieved from Sub?

An unbound method can be called only after it is bound to an object
whose class is a subclass of the original object’s class - that is the
object to which the method was originally bound, i.e. before you called
{{ unbound }} (see ‘Programming Ruby 1.9’, page 715).

Igor P. wrote in post #1082653:

An unbound method can be called only after it is bound to an object
whose class is a subclass of the original object’s class - that is the
object to which the method was originally bound, i.e. before you called
{{ unbound }} (see ‘Programming Ruby 1.9’, page 715).

This does not answer the question.

Mean L. wrote in post #1082655:

This does not answer the question.

How comes? It is the rule, that you can not bind a method to anything
but to the object that is an instance of a subclass of the class of the
original object. You are trying to bind it to an instance of its parent
or the superclass.

See, if you make a subclass ‘A’ of your ‘Sub’, all works as spelled out
by the Ruby rules, however if you try to bind to the object whose class
is the parent of your ‘Sub’ you get the error, which BTW, spells out
precisely what you missed here:

class Base; def foo; puts “in Base”; end; end
class Sub < Base; end
class A < Sub; end

base_foo = Base.instance_method :foo
sub_foo = Sub.instance_method :foo

base_foo.bind(Base.new).call #=> “in Base”
sub_foo.bind(A.new).call #=> “in Base”

sub_foo.bind(Base.new).call #=> ./b-u_test.rb:24:in bind': \ bind argument must be an instance \ of Sub (TypeError) \ from ./b-u_test.rb:24:in

Regards, igor

Igor P. wrote in post #1082666:

Mean L. wrote in post #1082655:

This does not answer the question.

How comes?

Because “it’s the rule” is a not a meaningful answer to why?

If you don’t know why, that’s ok, neither do I, that just means you need
to wait for an answer instead of repeating, “it’s the rule”.

AFAICT it should be sufficient to test that the object you are binding
to is_a?(owner) (Base.new.is_a?(sub_foo.owner))

This would also make base_foo and sub_foo equal as they refer to the
same foo in base.

Ryan D. wrote in post #1082683:

On Nov 3, 2012, at 16:30 , Mean L. [email protected] wrote:

to wait for an answer instead of repeating, “it’s the rule”.

AFAICT it should be sufficient to test that the object you are binding
to is_a?(owner) (Base.new.is_a?(sub_foo.owner))

This would also make base_foo and sub_foo equal as they refer to the
same foo in base.

Unfortunately, the answer really is because “it’s the rule”.

The slightly longer answer is “because Matz is worried we’ll try to bind
a C method (eg Array#join) to a different class and cause a crash”.

I am not following this logic. Binding a method to an object that is_a?
method’s owner, should be completely safe, there is no danger of
crashes. I think you are thinking of an even looser (duck) binding,
which may have merits, but it’s not what I am asking about.

Mean L. wrote in post #1082678:

This would also make base_foo and sub_foo equal as they refer to the
same foo in base.

{{ Base.new.is_a?(sub_foo.owner) }} does not give you the right answer
because the rule demands that the following holds:

{{ Base.new.is_a?(sub_foo.owner) && Base != Sub.superclass }}.

And yes, I do not know nor care, why “why does UnboundMethod need to
remember the class it was retrieved from (not merely owner)?”. At least
not the way you asked it. This question is to vague, and it turned out
also irrelevant in the relationship to the code you gave us in your
original post, as well as to your comment in your AFAICT latter. If you
understand the rule, you can tell that your

{{ Base.new.is_a?(sub_foo.owner) }}

is not the same as what demands the rule.

Cheers, igor

Igor P. wrote in post #1082685:

Mean L. wrote in post #1082678:

This would also make base_foo and sub_foo equal as they refer to the
same foo in base.

{{ Base.new.is_a?(sub_foo.owner) }} does not give you the right answer
because the rule demands that the following holds:

{{ Base.new.is_a?(sub_foo.owner) && Base != Sub.superclass }}.

And yes, I do not know nor care, why “why does UnboundMethod need to
remember the class it was retrieved from (not merely owner)?”.

Since you neither know nor care to know, it would have been sensible to
move on, and not repeat, “it’s the rule”, yet again.

On Nov 3, 2012, at 16:30 , Mean L. [email protected] wrote:

to wait for an answer instead of repeating, “it’s the rule”.

AFAICT it should be sufficient to test that the object you are binding
to is_a?(owner) (Base.new.is_a?(sub_foo.owner))

This would also make base_foo and sub_foo equal as they refer to the
same foo in base.

Unfortunately, the answer really is because “it’s the rule”.

The slightly longer answer is “because Matz is worried we’ll try to bind
a C method (eg Array#join) to a different class and cause a crash”. I’ve
proposed the change that gets rid of “the rule” and it got shot down
with this explanation. Why we can’t just say that the rule is only in
effect for C methods is beyond me.

I think it’d be a fantastic change to allow for agent / prototype-based
/ genetic programming.

Igor P. wrote in post #1082688:

I obviously, do care about the correct question:)

I see, I now understand your malfunction. When you encounter a question
which you can’t and don’t even want to be able to answer, you answer
instead a different question which you think you are able to answer.

Here’s an activity that might appeal to you, create a sock puppet and
ask all the “correct” questions you know the answers to, then answer
them yourself. That should keep you busy enough not to flood other
threads.

Stop being arseholes, folks. It’s only a ruby forum. Chill.

Mean L. wrote in post #1082686:

Since you neither know nor care to know, it would have been sensible to
move on, and not repeat, “it’s the rule”, yet again.

Perhaps you should have noticed that only after a few posts we figured
what exactly is bothering you. And after all it is your refusal to
understand the rule. I have given you exactly the answer, which you
asked, after your AFAICT revealed your mistake. Your assumption:

{{ Base.new.is_a?(sub_foo.owner) }}

is incorrect, and you should replace it with:

{{ Base.new.is_a?(sub_foo.owner) && Base != Sub.superclass }}

I obviously, do care about the correct question:)

Take it easy, igor

Mean L. wrote in post #1082692:

“why does UnboundMethod need to remember the class it was retrieved
from (not merely owner)?”

Because, the UnboundMethod can not be bound to an object that is not
instantiated as subclass of the class of the owner of the unbound
method. That is the requirement if you wish to bound it, period!

Igor P. wrote in post #1082696:

Mean L. wrote in post #1082692:

“why does UnboundMethod need to remember the class it was retrieved
from (not merely owner)?”

Because, the UnboundMethod can not be bound to an object that is not
instantiated as subclass of the class of the owner of the unbound
method. That is the requirement if you wish to bound it, period!

I thought you at least understood the rule as it is, since you kept
referring to it over and over. Let’s examine what you posted:

“can not be bound to an object that is not” – cancelling the double
negative gives us:

“the UnboundMethod can only be bound to an object that is an instance of
a subclass of the owner class”

This is false on two separate counts:

  1. It’s not the owner that matters, but the class via which you retrieve
    the method (the one you call instance_method on), they are not the same.

class Base; def foo; end end
class Sub < Base; end
class SubSub < Sub; end

base_foo = Base.instance_method :foo
sub_foo = Sub.instance_method :foo
sub_sub_foo = SubSub.instance_method :foo.

sub_sub_foo.bind(Sub.new).call

In the above example, the owner of sub_sub_foo (sub_sub_foo.owner) is
Base, Sub.new is an instance of Sub which is a subclass of Base, which
satisfies your misconception/misstatement of the current rule.

  1. even if we replace in you misstated rule, “owner” by “class on which
    instance_method was called to retrieve the method”, it is still wrong
    because it refers to subclass, instead of subclass or same class.

Igor P. wrote in post #1082715:

Mean L. wrote in post #1082704:

“the UnboundMethod can only be bound to an object that is an instance of
a subclass of the owner class”

I never wrote this! The word owner refers an object of the class and not
a class. To be exact my wording is:

“owner of the unbound method” were your words. And there is no ambiguity
as to what that is. It is the class returned by the “owner” method of
the UnboundMethod object, and it is in fact a class or a module that
defines the method in question, not any instance. You are rather
confused, and it’s pointless to continue this.

I suggest you ignore Igor, as he has already proven he is a troll in
earlier threads.

– Matma R.

Mean L. wrote in post #1082704:

“the UnboundMethod can only be bound to an object that is an instance of
a subclass of the owner class”

I never wrote this! The word owner refers an object of the class and not
a class. To be exact my wording is:

the UnboundMethod can not be bound to an object that is not instantiated
as subclass of the class of the owner of the unbound method.

Cancelling the double negation below is what I said originally when I
quoted the book ‘Programming Ruby 1.9’, page 715!

“can not be bound to an object that is not” – cancelling the double
negative gives us:

“the UnboundMethod can only be bound to an object that is an instance of
a subclass of the owner class”

This is false on two separate counts:

Like I said, i wrote this originally, and this is the rule, spelled out
in ‘Programming Ruby 1.9’, page 715! How can it be wrong, if it is
Ruby’s requirement?

BTW, the same requirement is expressed in the statement you are
ignoring:

{{ Base.new.is_a?(sub_foo.owner) && Base != Sub.superclass }}

Following is this condition in the example using your code snippet from
your first post in this thread:

class Base; def foo; puts “in Base”; end; end
class Sub < Base; end
class A < Sub; end

base_foo = Base.instance_method :foo
sub_foo = Sub.instance_method :foo
base_foo.bind(Base.new).call #=> “in Base”
sub_foo.bind(A.new).call #=> “in Base”

sub_foo.bind(Base.new).call
if Base.new.is_a?(sub_foo.owner) && Base != Sub.superclass

Comment this condition above out and you’ll get the error telling you
exactly what I am telling you namely:

./t-bind.rb:31:in bind': bind argument must be an instance \ of Sub (TypeError) from ./t-bind.rb:31:in

BTW ‘is_a’ here is not sufficiently restrictive relationship since it
must exclude the superclass!

Cheers, igor