Hi --

On Mon, 4 Apr 2005, Johan Holmberg wrote:

>
> Hi!
>
> I was trying to find out the "class methods" of some classes.
> Looking in the PickAxe I found out that there are at least three methods that 
> return almost the same thing for a class/module:
>
>    Object#singleton_methods(flag)
>    Object#public_methods(flag)
>    Object#methods(flag)
>
> So potentially we can get six (3 * 2) different results. To find out the 
> difference between all invocations, I ran the methods on all builitin 
> classes/modules, and compared the result. It turned out that I actually got 4 
> different results:
>
>    - methods(false) and singleton_methods(false)
>      give the same result
>
>    - singleton_methods(true)
>      gives a unique result
>
>    - public_methods(false)
>      gives a unique result
>
>    - methods(true) and public_methods(true)
>      give the same result
>
> The PickAxe said that Object#public_methods was a synonym for Object#methods. 
> This is apparently not true (or true only when the argument is "true").
>
> To me it seem like these methods have "degenerated" into something that is 
> almost impossible to explain. Neither the PickAxe nor the online-docs 
> explains it in a way so I can understand the differences. Can anyone explain 
> the logic behind these different methods and their results?

I can offer one observation that might account for some of this:

"singleton_methods(true)" means "singleton methods on this object or,
if the object is a Class, this object and its ancestral classes."  For
example:

   irb(main):001:0> class A; def A.x; end; end; class B < A; end
   => nil
   irb(main):002:0> B.singleton_methods(false)
   => []
   irb(main):003:0> B.singleton_methods(true)
   => ["x"]

I would argue that there is a bit of a contradiction here, arising
from the special case of inheritance.  x is not really a singleton
method of B; it's a singleton method of B's superclass, and the rules
of inheritance allow the (arguably anomalous) behavior that the
subclass can serve as the receiver for what would otherwise be a truly
singleton method.

I believe this is the only scenario where, after doing this:

   def obj.meth; end

any object other than obj can call meth.  In other words, a Class's
singleton methods ("class methods") don't quite behave in a singleton
fashion.

These true/false flags are awfully opaque, so
B.singleton_methods(true) still sounds like it should be B's singleton
methods, not those of B and other object(s).  Aside from the length of
the method name, it should be something like:

   B.singleton_and_inherited_singleton_methods

to acknowledge that B is in the unusual position of being able to
handle calls to the singleton methods of certain other objects.

Or -- B.class_methods.  I really like the fact that class methods in
Ruby are just an application of the more general singleton-method
principle.  But if they are in fact different at the language level,
it might be best to label them.


David

-- 
David A. Black
dblack / wobblini.net