Singleton methods vs. meta instance methods

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

On Sat, Dec 13, 2008 at 6:25 AM, Daniel DeLorme [email protected]
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 :wink:
----------------------------------------------- 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

Robert D. 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”]

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

On Sat, Dec 13, 2008 at 10:50 PM, Brian C. [email protected]
wrote:

Robert D. 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 :wink:
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

On Sun, Dec 14, 2008 at 11:51 AM, Daniel DeLorme [email protected]
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

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.

On Sun, Dec 14, 2008 at 12:16 PM, Brian C. [email protected]
wrote:

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

Hi –

On Sun, 14 Dec 2008, Brian C. 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 :slight_smile:

David

Robert D. wrote:

On Sat, Dec 13, 2008 at 10:50 PM, Brian C. [email protected]
wrote:

Robert D. 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 :slight_smile: 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.

Robert D. 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”]

Hi –

On Sun, 14 Dec 2008, Brian C. 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

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 -

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

Currently we have obj.singleton_methods for 1 and klass.instance_methods
for (false=>2, true=>3)

Hi –

On Mon, 15 Dec 2008, Brian C. 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 :slight_smile: does not mean that, when
the receiver is a singleton class.

David