Forum: Ruby singleton methods vs. meta instance methods

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
E0526a6bf302e77598ef142d91bdd31c?d=identicon&s=25 Daniel DeLorme (Guest)
on 2008-12-13 06:33
(Received via mailing list)
If I understand the ruby object model correctly, then an object's
singleton methods are defined as the instance methods of that object's
meta/singleton class. So I tried to confirm this:

obj = Object.new
obj_meta = (class << obj;self;end)
def obj.foobar; end
obj.singleton_methods            #=> ["foobar"]
obj_meta.instance_methods(false) #=> ["foobar"]

So far so good. But if I try the same thing with a class:

class A; end
A_meta = (class << A;self;end)
def A.foobar; end
A.singleton_methods            #=> ["foobar"]
A_meta.instance_methods(false) #=> ["allocate", "superclass", "foobar",
"new"]

I understand why those 3 extra methods appear, but in that case
shouldn't they also appear as part of A.singleton_methods? Furthermore
this does not happen with builtin classes. Does anyone have an
explanation for what is going on here?

Daniel
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2008-12-13 21:01
(Received via mailing list)
On Sat, Dec 13, 2008 at 6:25 AM, Daniel DeLorme <dan-ml@dan42.com>
wrote:
> So far so good. But if I try the same thing with a class:
> happen with builtin classes. Does anyone have an explanation for what is
> going on here?
>
> Daniel
>
Daniel first, I had some difficulties to see what puzzles you. The
fact that meta methods are not singleton methods made perfectly sense,
but than I tried to define meta methods, which you did not, and then I
was as puzzled as you were ;)
----------------------------------------------- 8<
------------------------
507/15 > cat test1.rb && ruby test1.rb
#!/usr/bin/ruby
# vim: sw=2 ts=2 ft=ruby expandtab tw=0 nu syn=on:
# file: test1.rb

def all_methods an_obj
  p(
    { :name => an_obj.name,
      :meta => class << an_obj; instance_methods( false ).sort end,
      :single => an_obj.singleton_methods( false ).sort }
  )
end


def Object.answer; 42 end
def (A=Class::new).answer; 42 end
all_methods Object
all_methods A

class << Object; def almost; 41 end end
class << A; def almost; 41 end end
all_methods Object
all_methods A
{:meta=>["allocate", "answer", "new", "superclass"],
:single=>["answer"], :name=>"Object"}
{:meta=>["allocate", "answer", "new", "superclass"],
:single=>["answer"], :name=>"A"}
{:meta=>["allocate", "almost", "answer", "new", "superclass"],
:single=>["almost", "answer"], :name=>"Object"}
{:meta=>["allocate", "almost", "answer", "new", "superclass"],
:single=>["almost", "answer"], :name=>"A"}
------------------------------------------------ >8
---------------------------------------------------

So you are right it does not seem possible to create that kind of
diversity ourselves.
I could however not see the difference between A and Object, can you
explain please?

Cheers
Robert

>



--
Il computer non è una macchina intelligente che aiuta le persone
stupide, anzi, è una macchina stupida che funziona solo nelle mani
delle persone intelligenti.
Computers are not smart to help stupid people, rather they are stupid
and will work only if taken care of by smart people.

Umberto Eco
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-13 22:57
Robert Dober wrote:
> I could however not see the difference between A and Object, can you
> explain please?

The OP used an *instance* of class Object, not Object itself, and
compared it with class A, which is an instance of class Class.

Perhaps it's clearer if written thus:

obj = Object.new
obj_meta = (class << obj;self;end)
def obj.foobar; end
p obj.singleton_methods            #=> ["foobar"]
p obj_meta.instance_methods(false) #=> ["foobar"]

a = Class.new
a_meta = (class << a;self;end)
def a.foobar; end
p a.singleton_methods            #=> ["foobar"]
p a_meta.instance_methods(false) #=> ["allocate", "superclass",
"foobar", "new"]
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-13 23:10
Daniel DeLorme wrote:
> Furthermore this does not happen with builtin classes.

I'm not sure what you mean by that part. I get the same if I use String
instead of your class A:

a = String
a_meta = (class << a;self;end)
def a.foobar; end
p a.singleton_methods
p a_meta.instance_methods(false)

with 1.8.6p114 I get:
["foobar"]
["allocate", "foobar", "superclass", "new"]

with 1.9.1-preview2 I get:
[:try_convert, :foobar]
[:try_convert, :foobar, :allocate, :new, :superclass]

But notice what happens if I try an *instance* of String (which is
comparable to what you were doing with an *instance* of class Object)

a = String.new
a_meta = (class << a;self;end)
def a.foobar; end
p a.singleton_methods(false)
p a_meta.instance_methods(false)

["foobar"]
["split", "rstrip!", "to_sym", "swapcase", "chop", "foobar", "empty?",
"swapcase!", "to_f", "casecmp", "rindex", "intern", "tr", "to_s",
"reverse!", "strip!", "match", "hex", "each", "include?", "slice",
"next!", "*", "downcase!", "downcase", "sub", "+", "=~", "upto",
"concat", "lstrip", "each_byte", "succ!", "chop!", "size", "dump",
"rjust", "squeeze", "delete!", "eql?", "next", "reverse", "sub!",
"insert", "chomp", "[]", "inspect", "tr!", "replace", "[]=", "scan",
"tr_s", "lstrip!", "succ", "<<", "oct", "gsub", "capitalize!", "to_i",
"hash", "capitalize", "crypt", "index", "chomp!", "rstrip", "sum",
"upcase!", "center", "upcase", "count", "squeeze!", "unpack", "<=>",
"strip", "==", "length", "gsub!", "each_line", "slice!", "ljust",
"to_str", "%", "delete", "tr_s!"]

So you can see the instance methods of the object's metaclass include
the instance methods of that object's class. From one point of view this
seems reasonable to me; the metaclass is like a 'private subclass' to
the real class.

From another point of view, you might expect instance_methods(false) not
to return those methods. But I think that just explains why we have a
separate singleton_methods method - if you *really* want just the
singleton methods, not including the methods of the concrete class, call
that.
E0526a6bf302e77598ef142d91bdd31c?d=identicon&s=25 Daniel DeLorme (Guest)
on 2008-12-14 12:00
(Received via mailing list)
Brian Candler wrote:
> Daniel DeLorme wrote:
>> Furthermore this does not happen with builtin classes.
>
> I'm not sure what you mean by that part. I get the same if I use String
> instead of your class A:

You're right, I can't reproduce this anymore. It seems I got confused at
some point in my irb session.

> ["split", "rstrip!", "to_sym", "swapcase", "chop", "foobar", "empty?",
[snip]
> singleton methods, not including the methods of the concrete class, call
> that.

Thank you for the explanation, it does make a lot more sense now. I'm of
the second point of view; I would expect instance_methods(*true*) to
return those extra methods, but not instance_methods(*false*). But POLS
is relative, and now that I understand this behavior I can see why the
"allocate", "new" and "superclass" methods were present in A's singleton
class' instance methods; those are indeed the instance methods defined
in Class:
   Class.instance_methods(false) #=> ["allocate", "superclass", "new"]

So it seems that
   x.meta.instance_methods(false) == x.singleton_methods +
   x.class.instance_methods(false)

I was missing that last part...

Daniel
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2008-12-14 12:03
(Received via mailing list)
On Sat, Dec 13, 2008 at 10:50 PM, Brian Candler <b.candler@pobox.com>
wrote:
> Robert Dober wrote:
>> I could however not see the difference between A and Object, can you
>> explain please?
>
> The OP used an *instance* of class Object, not Object itself, and
> compared it with class A, which is an instance of class Class.
Brian I referred to exactly the same thing you do in your next post,
just do a %s/Object/String/g.
I did see his first point, although he did not give an example for the
inconsistency.
Confusing is it not ;)
> a_meta = (class << a;self;end)
> def a.foobar; end
> p a.singleton_methods            #=> ["foobar"]
> p a_meta.instance_methods(false) #=> ["allocate", "superclass",
> "foobar", "new"]
No really I feel up to here we are just fine, the problem starts when
we define something in the metaclass and
see it in the singleton class, thus we can ask ourself how is it
possible that we have the difference you showed in the last two lines.
>
> --
> Posted via http://www.ruby-forum.com/.
>
>



--
Il computer non è una macchina intelligente che aiuta le persone
stupide, anzi, è una macchina stupida che funziona solo nelle mani
delle persone intelligenti.
Computers are not smart to help stupid people, rather they are stupid
and will work only if taken care of by smart people.

Umberto Eco
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2008-12-14 12:19
(Received via mailing list)
On Sun, Dec 14, 2008 at 11:51 AM, Daniel DeLorme <dan-ml@dan42.com>
wrote:

>>> From another point of view, you might expect instance_methods(false) not
>>
>> to return those methods. But I think that just explains why we have a
>> separate singleton_methods method - if you *really* want just the singleton
>> methods, not including the methods of the concrete class, call that.
>
> Thank you for the explanation, it does make a lot more sense now.

Does it? I was of Brian's opinion until I added a method to the meta
class and it showed up in the singleton class, that definitely broke
this explanation and now I am really interested how this happens.
To be clear I am not surprised about what you have shown so far. I am
surprised that by adding a method to the metaclass it shows up in the
singleton!!!

So we are as confused as ever but I am certain that we are confused
about more important things and on a much higher level ;).

R.

--
Il computer non è una macchina intelligente che aiuta le persone
stupide, anzi, è una macchina stupida che funziona solo nelle mani
delle persone intelligenti.
Computers are not smart to help stupid people, rather they are stupid
and will work only if taken care of by smart people.

Umberto Eco
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-14 12:24
Robert Dober wrote:
> On Sat, Dec 13, 2008 at 10:50 PM, Brian Candler <b.candler@pobox.com>
> wrote:
>> Robert Dober wrote:
>>> I could however not see the difference between A and Object, can you
>>> explain please?
>>
>> The OP used an *instance* of class Object, not Object itself, and
>> compared it with class A, which is an instance of class Class.
> Brian I referred to exactly the same thing you do in your next post,
> just do a %s/Object/String/g.

Maybe I overlooked something - all these classes and metaclasses can get
pretty confusing :-) I was comparing the part of your code where you
wrote:

def Object.answer; 42 end

with the OP's which had:

obj = Object.new
def obj.foobar; end

> No really I feel up to here we are just fine, the problem starts when
> we define something in the metaclass and
> see it in the singleton class

I'm not sure what the distinction is you're trying to make between
metaclass and singleton class. I believe they are two names for the same
thing.

The OP was trying to demonstrate that "an object's singleton methods are
defined as the instance methods of that object's meta/singleton class"

This was demonstrated successfully, given the additional info that
metaclass.instance_methods(false) returns both the instance methods in
the metaclass plus the instance methods of the actual class.

However, obj.singleton_methods returns only the instance methods in
obj.metaclass.

At least, that's how I understand it at the moment - I am happy to be
corrected if this is wrong.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2008-12-14 12:44
(Received via mailing list)
On Sun, Dec 14, 2008 at 12:16 PM, Brian Candler <b.candler@pobox.com>
wrote:
<snip>
> This was demonstrated successfully, given the additional info that
> metaclass.instance_methods(false) returns both the instance methods in
> the metaclass plus the instance methods of the actual class.
>
> However, obj.singleton_methods returns only the instance methods in
> obj.metaclass.
Yes it comes down to this and hopefully you are right and I am wrong,
because I am getting headaches already ;).
But... alas
you say that a meta.instance_methods returns both instance methods in
the metaclass plus the instance methods
of the actual class. I agree, you have shown this, however, :new,
:allocate & :superclass are instance methods of the metaclass, not of
the actual class, or are they not?
This is for the example A
{:meta=>["allocate", "answer", "new", "superclass"],
:single=>["answer"], :name=>"A"}
new is defined in class << A,

no wait a moment it is not yet  I guess I see the end of the light and
the beginning of the tunnel

def (A=Class::new).answer; 42 end
def A.new; allocate end
all_methods A
{:meta=>["allocate", "almost", "answer", ***"new"***, "superclass"],
:single=>["almost", "answer", ***"new"***], :name=>"A"}

Great job Brian I got it, thanx.
Cheers
Robert


>
> At least, that's how I understand it at the moment - I am happy to be
> corrected if this is wrong.
> --
> Posted via http://www.ruby-forum.com/.
>
>



--
Il computer non è una macchina intelligente che aiuta le persone
stupide, anzi, è una macchina stupida che funziona solo nelle mani
delle persone intelligenti.
Computers are not smart to help stupid people, rather they are stupid
and will work only if taken care of by smart people.

Umberto Eco
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2008-12-14 14:07
(Received via mailing list)
Hi --

On Sun, 14 Dec 2008, Brian Candler wrote:

> p a_meta.instance_methods(false)
> comparable to what you were doing with an *instance* of class Object)
> "reverse!", "strip!", "match", "hex", "each", "include?", "slice",
> So you can see the instance methods of the object's metaclass include
> the instance methods of that object's class. From one point of view this
> seems reasonable to me; the metaclass is like a 'private subclass' to
> the real class.
>
>> From another point of view, you might expect instance_methods(false) not
> to return those methods. But I think that just explains why we have a
> separate singleton_methods method - if you *really* want just the
> singleton methods, not including the methods of the concrete class, call
> that.

I've never liked the "false" flag thing, since it's obscure to begin
with. If it doesn't actually mean "defined in exactly this class",
then I'm not sure what purpose it serves at all.

(Don't mean to sound curmudgeonly -- am multi-tasking, which almost
always means I shouldn't post to ruby-talk since whatever the main
point is is probably zooming past me :-)


David
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-14 14:20
Robert Dober wrote:
> But... alas
> you say that a meta.instance_methods returns both instance methods in
> the metaclass plus the instance methods
> of the actual class. I agree, you have shown this, however, :new,
> :allocate & :superclass are instance methods of the metaclass, not of
> the actual class, or are they not?

I believe that they are instance methods of the actual class "Class".

irb(main):002:0> Class.instance_methods(false)
=> ["allocate", "superclass", "new"]
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2008-12-14 14:31
(Received via mailing list)
Hi --

On Sun, 14 Dec 2008, Brian Candler wrote:

> irb(main):002:0> Class.instance_methods(false)
> => ["allocate", "superclass", "new"]

Here's a demo of the consistency from the Class case to the SomeClass
case. I'm still not convinced that it's the ideal behavior.

$ cat sing.rb
class Object
   def singleton_class; class << self; self; end; end
end

class A
   def x; end
end

an_a = A.new
def an_a.y; end

p A.instance_methods(false)
p an_a.singleton_class.instance_methods(false)

$ ruby sing.rb
["x"]
["y", "x"]

$ ruby -pe 'gsub(/A/,"Class")' sing.rb | ruby -
["allocate", "superclass", "new", "x"]
["y", "allocate", "superclass", "new", "x"]


David
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-14 18:08
David A. Black wrote:
> Here's a demo of the consistency from the Class case to the SomeClass
> case. I'm still not convinced that it's the ideal behavior.

Why not? It seems both consistent and reasonable to me. Similarly:

$ ruby -pe 'gsub(/A/,"String")' sing.rb | ruby -
F53b05cdbdf561cfe141f69b421244f3?d=identicon&s=25 David A. Black (Guest)
on 2008-12-14 18:19
(Received via mailing list)
Hi --

On Mon, 15 Dec 2008, Brian Candler wrote:

> David A. Black wrote:
>> Here's a demo of the consistency from the Class case to the SomeClass
>> case. I'm still not convinced that it's the ideal behavior.
>
> Why not? It seems both consistent and reasonable to me. Similarly:
>
> $ ruby -pe 'gsub(/A/,"String")' sing.rb | ruby -

Right; that's what I was demonstrating (the consistency, in that
instances of Class, A, String... all behave the same way). My problem
with what we're seeing is that I think the "false" flag should mean
"defined in exactly this class" -- and, in fact, that's what I thought
it did mean. Apparently it (consistently :-) does not mean that, when
the receiver is a singleton class.


David
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2008-12-14 18:33
David A. Black wrote:
> My problem
> with what we're seeing is that I think the "false" flag should mean
> "defined in exactly this class" -- and, in fact, that's what I thought
> it did mean. Apparently it (consistently :-) does not mean that, when
> the receiver is a singleton class.

Oh OK, that's the point Daniel was making too.

I guess instance_methods could take a tristate option:

1. instance methods of just this (singleton) class
2. instance methods of this (singleton) class plus
   the actual Class it derives from
3. instance methods of the singleton class, the Class
   and its ancestors

But as you say, having (true) and (false) is bad enough already :-)

Currently we have obj.singleton_methods for 1 and klass.instance_methods
for (false=>2, true=>3)
This topic is locked and can not be replied to.