Can't bind a singleton method to a subclass?

The behavior of this snippet doesn’t make sense to me:

class A
def A.class_method
puts “Class method worked in #{self}”
end
end

class B < A; end

aklass = (class << A; self; end)
bklass = (class << B; self; end)

p RUBY_VERSION

A.class_method
B.class_method

p A.method(:class_method)
p B.method(:class_method)
p aklass.instance_method(:class_method)
p bklass.instance_method(:class_method)
p A.method(:class_method).unbind
p B.method(:class_method).unbind
p A.method(:class_method).unbind.bind(A)
p B.method(:class_method).unbind.bind(B)

The output (for me) is:

“1.8.4”
Class method worked in A
Class method worked in B
#<Method: A.class_method>
#<Method: B(A).class_method>
#<UnboundMethod: #Class:A#class_method>
#<UnboundMethod: #Class:A#class_method>
#<UnboundMethod: #Class:A#class_method>
#<UnboundMethod: #Class:A#class_method>
#<Method: A.class_method>
/workplace2/test.rb:24:in `bind’: singleton method called for a
different object (TypeError)
from /workplace2/test.rb:24

In my mind, the last call should succeed, instead of raising an error.
Is it just plain impossible to re-bind the method to yield a #<Method:
B(A).class_method>?

Hi –

On Wed, 8 Nov 2006, David Walker wrote:

aklass = (class << A; self; end)
p bklass.instance_method(:class_method)
#<Method: A.class_method>
In my mind, the last call should succeed, instead of raising an error.
Is it just plain impossible to re-bind the method to yield a #<Method:
B(A).class_method>?

The fact that B can call A.class_method is due to the special-casing
of singleton classes of Class objects; it’s the one case where a given
object can execute singleton methods of another object. But those
singleton methods still belong, unambiguously, to the first object, A.
The reason B can call them is that A’s singleton class serves as the
superclass of B’s singleton class – so class_method lies on the
method look-up path of B. But class_method is still defined only in
A’s singleton class.

David

On 11/7/06, [email protected] [email protected] wrote:

The fact that B can call A.class_method is due to the special-casing
of singleton classes of Class objects; it’s the one case where a given
object can execute singleton methods of another object. But those
singleton methods still belong, unambiguously, to the first object, A.
The reason B can call them is that A’s singleton class serves as the
superclass of B’s singleton class – so class_method lies on the
method look-up path of B. But class_method is still defined only in
A’s singleton class.

Thanks for the info. That’s mostly what I thought - I guess I should
have said, “This seems silly to me,” not, “This doesn’t make sense to
me.” :slight_smile:

How, though, is this a special case? For instance methods, you can
bind an instance method to any object who’s class is <= the class the
method is defined on. Why should it be different for singletons? I.e.
I have an instance method (instance from the perspective of the
singleton class A), I should be able to bind it to an object who’s
class is a subclass of the class the instance is defined on. If A’s
singleton class is a superclass of B’s singleton class (which it ought
to be) then this relation holds. I think. :slight_smile:

In any case, “B.method(:class_method)” gave me a #<Method:
B(A).class_method>. My original question still stands: is there no way
to recover this binding once it’s been unbound?

On Wed, 8 Nov 2006 [email protected] wrote:

The fact that B can call A.class_method is due to the special-casing of
singleton classes of Class objects; it’s the one case where a given object
can execute singleton methods of another object. But those singleton
methods still belong, unambiguously, to the first object, A. The reason B
can call them is that A’s singleton class serves as the superclass of B’s
singleton class – so class_method lies on the method look-up path of B.
But class_method is still defined only in A’s singleton class.

still, quiet odd that one can do this

p B.method(:class_method).unbind

meaning, it’s strange that you can ‘unbind’ from a class something which
cannot be bound to it and yet must have been for the initial call to
‘unbind’
to succeed - a contradiction.

interesting.

-a

Hi –

On Wed, 8 Nov 2006, David Walker wrote:

Thanks for the info. That’s mostly what I thought - I guess I should
have said, “This seems silly to me,” not, “This doesn’t make sense to
me.” :slight_smile:

How, though, is this a special case?

What I mean is: the fact that you can call B.class_method, even though
class_method is a singleton method of an object other than B, is a
special dispensation for class objects.

For instance methods, you can
bind an instance method to any object who’s class is <= the class the
method is defined on. Why should it be different for singletons? I.e.
I have an instance method (instance from the perspective of the
singleton class A), I should be able to bind it to an object who’s
class is a subclass of the class the instance is defined on. If A’s
singleton class is a superclass of B’s singleton class (which it ought
to be) then this relation holds. I think. :slight_smile:

I guess it’s just a matter of how the logic cascades. Forbidding a
rebinding of a singleton method on a different object takes precedence
over the special situation where class singleton methods are sort of
not really singleton (i.e., can be called by subclasses).

In any case, “B.method(:class_method)” gave me a #<Method:
B(A).class_method>. My original question still stands: is there no way
to recover this binding once it’s been unbound?

Maybe, but not that I can think of.

David

Hi –

On Wed, 8 Nov 2006, [email protected] wrote:

But class_method is still defined only in A’s singleton class.

still, quiet odd that one can do this

p B.method(:class_method).unbind

meaning, it’s strange that you can ‘unbind’ from a class something which
cannot be bound to it and yet must have been for the initial call to
‘unbind’
to succeed - a contradiction.

I think it’s not so much that you’re unbinding it from B, as that
you’re grabbing it through B. So, by the time you unbind it, it
doesn’t “know” that you got it that way; it’s just a Method object,
and it allows itself to be unbound. I’d say that’s a side-effect of
the fact that A’s singleton methods can be got at via B at all.

Going the other way, though, it does “know” that you’re trying to bind
it to something other than the object in whose singleton class it’s
defined.

David

On Wed, 8 Nov 2006 [email protected] wrote:

I think it’s not so much that you’re unbinding it from B, as that you’re
grabbing it through B. So, by the time you unbind it, it doesn’t “know”
that you got it that way; it’s just a Method object, and it allows itself to
be unbound.

yeah. at first i thought that, but:

 harp:~ > cat a.rb
 class A
   def self.class_method() 42 end
 end
 class B < A; end

 p A.method(:class_method)
 p B.method(:class_method)


 harp:~ > ruby a.rb
 #<Method: A.class_method>
 #<Method: B(A).class_method>

so it seems like the method is aware that it’s receiver is B. but i
take your
point.

I’d say that’s a side-effect of the fact that A’s singleton
methods can be got at via B at all.

yes. put another way, and something i was be-moaning several years ago,
is
this:

 harp:~ > cat a.rb
 class A
   SINGLETON_CLASS = class << self
     self
   end
 end
 class B < A
   SINGLETON_CLASS = class << self
     self
   end
 end

 p B::SINGLETON_CLASS.ancestors

 harp:~ > ruby a.rb
 [Class, Module, Object, Kernel]

singleton classes should respect inheritence.

regards.

-a

On Wed, 8 Nov 2006 [email protected] wrote:

 SINGLETON_CLASS = class << self

I’m not sure what you mean here. Is it that ancestors doesn’t show
singleton classes?

i meant that B’s singleton class should inherit from A’s singleton class

  • the
    fact that it does not leads to all sorts of suprising behaviour…

-a

Hi –

On Wed, 8 Nov 2006, [email protected] wrote:

 end

[Class, Module, Object, Kernel]

singleton classes should respect inheritence.

I’m not sure what you mean here. Is it that ancestors doesn’t show
singleton classes?

i meant that B’s singleton class should inherit from A’s singleton
class - the fact that it does not leads to all sorts of suprising
behaviour…

I’m still not seeing where your example fits in with this (I assume
I’m just being thick and not seeing what’s right in front of me) –
but I’ll forge ahead and note that the question of the subclass
relation of singleton classes seems to have swung back and forth. In
1.8.2, this was true (given the usual singleton_class method):

B.singleton_class.superclass == A.singleton_class

and it’s true in fairly recent 1.9, but not true in 1.8.5. I have no
idea why not. B.meth still looks in A’s singleton class for “meth”,
but apparently inheritance is not used as the mechanism.

David

Hi –

On Wed, 8 Nov 2006, [email protected] wrote:

yeah. at first i thought that, but:

harp:~ > ruby a.rb
#<Method: A.class_method>
#<Method: B(A).class_method>

so it seems like the method is aware that it’s receiver is B. but i take
your point.

Interesting. The dot is the singleton-method indicator in that
notation:

irb(main):013:0> obj = Object.new
=> #Object:0xb7f04aa8
irb(main):014:0> def obj.x; end
=> nil
irb(main):015:0> obj.method(:x)
=> #<Method: #Object:0xb7f04aa8.x>

In your example, it’s A.class_method and not
#Class:0xabcdef.class_method. But it still really means the
singleton class of A. I guess it’s all in the service of allowing for
that special case singleton-of-Class-object thing.

 end

[Class, Module, Object, Kernel]

singleton classes should respect inheritence.

I’m not sure what you mean here. Is it that ancestors doesn’t show
singleton classes?

David

On Wed, 8 Nov 2006 [email protected] wrote:

B.singleton_class.superclass == A.singleton_class

yup - this is what i was saying is needed.

and it’s true in fairly recent 1.9, but not true in 1.8.5.

right - so we wait :wink:

-a

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs