Can't bind a singleton method to a subclass?

Discussion in 'Ruby' started by David Walker, Nov 8, 2006.

  1. David Walker

    David Walker Guest

    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>?

    --
    =D ave
    David Walker, Nov 8, 2006
    #1
    1. Advertising

  2. David Walker

    Guest

    Hi --

    On Wed, 8 Nov 2006, David Walker wrote:

    > 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>?


    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

    --
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    , Nov 8, 2006
    #2
    1. Advertising

  3. David Walker

    Guest

    On Wed, 8 Nov 2006 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
    --
    my religion is very simple. my religion is kindness. -- the dalai lama
    , Nov 8, 2006
    #3
  4. David Walker

    David Walker Guest

    On 11/7/06, <> 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." :)

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

    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?

    --
    =D ave
    David Walker, Nov 8, 2006
    #4
  5. David Walker

    Guest

    Hi --

    On Wed, 8 Nov 2006, David Walker wrote:

    > On 11/7/06, <> 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." :)
    >
    > 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. :)


    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

    --
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    , Nov 8, 2006
    #5
  6. David Walker

    Guest

    Hi --

    On Wed, 8 Nov 2006, wrote:

    > On Wed, 8 Nov 2006 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.


    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

    --
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    , Nov 8, 2006
    #6
  7. David Walker

    Guest

    On Wed, 8 Nov 2006 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
    --
    my religion is very simple. my religion is kindness. -- the dalai lama
    , Nov 8, 2006
    #7
  8. David Walker

    Guest

    Hi --

    On Wed, 8 Nov 2006, wrote:

    > On Wed, 8 Nov 2006 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.


    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.

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


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


    David

    --
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    , Nov 8, 2006
    #8
  9. David Walker

    Guest

    On Wed, 8 Nov 2006 wrote:

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

    >
    > 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
    --
    my religion is very simple. my religion is kindness. -- the dalai lama
    , Nov 8, 2006
    #9
  10. David Walker

    Guest

    Hi --

    On Wed, 8 Nov 2006, wrote:

    > On Wed, 8 Nov 2006 wrote:
    >
    >>> 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.

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

    --
    David A. Black |
    Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
    DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
    [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
    [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
    , Nov 8, 2006
    #10
  11. David Walker

    Guest

    On Wed, 8 Nov 2006 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 ;-)

    -a
    --
    my religion is very simple. my religion is kindness. -- the dalai lama
    , Nov 8, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jstorta
    Replies:
    3
    Views:
    441
    jstorta
    Feb 20, 2006
  2. Lou Pecora
    Replies:
    8
    Views:
    343
    Lou Pecora
    May 25, 2006
  3. S.Volkov
    Replies:
    2
    Views:
    215
    S.Volkov
    Mar 12, 2006
  4. Trans
    Replies:
    8
    Views:
    320
    Robert Klemme
    Oct 23, 2008
  5. Fab

    Subclass of subclass

    Fab, Aug 9, 2012, in forum: C++
    Replies:
    0
    Views:
    395
Loading...

Share This Page