Class method in singleton_methods?

Hi group.

I've found that I have to query class methods like:

irb(main):001:0> class Foo
irb(main):002:1> def Foo.bar
irb(main):003:2> end
irb(main):004:1> end
=> nil
irb(main):005:0> Foo.singleton_methods
=> ["bar"]
irb(main):006:0>

It is interesting that a class method is actually a singleton method. I
know that there are tons of posting regarding metaclasses/objects.
Unfortunately, there are simply too many to read and understand all of
them. So, please forgive my naive question.

Here's the thing. I guess Foo is actually defined like:

irb(main):001:0> Foo = Class.new
=> Foo
irb(main):002:0> class << Foo
irb(main):003:1> def Foo.bar
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> Foo.singleton_methods
=> ["bar"]
irb(main):007:0>

Am I correct?

Sincerely,
Minkoo Seo

Hi --

Hi group.

I've found that I have to query class methods like:

irb(main):001:0> class Foo
irb(main):002:1> def Foo.bar
irb(main):003:2> end
irb(main):004:1> end
=> nil
irb(main):005:0> Foo.singleton_methods
=> ["bar"]
irb(main):006:0>

It is interesting that a class method is actually a singleton method. I
know that there are tons of posting regarding metaclasses/objects.
Unfortunately, there are simply too many to read and understand all of
them. So, please forgive my naive question.

Here's the thing. I guess Foo is actually defined like:

irb(main):001:0> Foo = Class.new
=> Foo
irb(main):002:0> class << Foo
irb(main):003:1> def Foo.bar
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> Foo.singleton_methods
=> ["bar"]
irb(main):007:0>

Am I correct?

A class method is indeed a singleton method of a Class object. The
term "class method" is really just a convenient label for this case,
because it occurs quite frequently.

The "def obj.meth" and "class << obj; def meth" techniques differ as
to the visibility of constants:

   X = 1
   class C
     X = 2
     def self.a
       puts X
     end
   end

   class << C
     def b
       puts X
     end
   end

   C.a # 2 (C::X)
   C.b # 1 (top-level X)

But in the vast majority of cases you can use them pretty much
interchangeably.

David

···

On Thu, 2 Mar 2006, Minkoo Seo wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

Hi --

Adding something to my previous reply:

Hi --

[...]

It is interesting that a class method is actually a singleton method. I
know that there are tons of posting regarding metaclasses/objects.
Unfortunately, there are simply too many to read and understand all of
them. So, please forgive my naive question.

[...]

Am I correct?

A class method is indeed a singleton method of a Class object. The
term "class method" is really just a convenient label for this case,
because it occurs quite frequently.

The one way in which class methods differ from other singleton methods
is that they're the only case, as far as I know, where more than one
object can call a specific singleton method:

   class C
     def self.x
     end
   end

   class D < C
   end

   D.x # OK, because D is a subclass of C, even though x is
           # a singleton method on another object (C)

The reason is this: C's singleton class (or "metaclass", as singleton
classes of Class objects are sometimes known) is the superclass of D's
singleton class. Since the method x resides in C's singleton class,
it is visible to instances of that singleton class (namely C), and to
instances of descendants of that singleton class (namely, D).

In other words, when you send the message "x" to D, D looks in its
singleton class, and then in the superclass of its singleton class --
and there it finds a method "x", and executes it.

David

···

On Thu, 2 Mar 2006, dblack@wobblini.net wrote:

On Thu, 2 Mar 2006, Minkoo Seo wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

dblack@wobblini.net wrote:

Hi --

> Hi group.
>
> I've found that I have to query class methods like:
>
> irb(main):001:0> class Foo
> irb(main):002:1> def Foo.bar
> irb(main):003:2> end
> irb(main):004:1> end
> => nil
> irb(main):005:0> Foo.singleton_methods
> => ["bar"]
> irb(main):006:0>
>
> It is interesting that a class method is actually a singleton method. I
> know that there are tons of posting regarding metaclasses/objects.
> Unfortunately, there are simply too many to read and understand all of
> them. So, please forgive my naive question.
>
> Here's the thing. I guess Foo is actually defined like:
>
> irb(main):001:0> Foo = Class.new
> => Foo
> irb(main):002:0> class << Foo
> irb(main):003:1> def Foo.bar
> irb(main):004:2> end
> irb(main):005:1> end
> => nil
> irb(main):006:0> Foo.singleton_methods
> => ["bar"]
> irb(main):007:0>
>
> Am I correct?

A class method is indeed a singleton method of a Class object. The
term "class method" is really just a convenient label for this case,
because it occurs quite frequently.

The "def obj.meth" and "class << obj; def meth" techniques differ as
to the visibility of constants:

   X = 1
   class C
     X = 2
     def self.a
       puts X
     end
   end

   class << C
     def b
       puts X
     end
   end

   C.a # 2 (C::X)
   C.b # 1 (top-level X)

The visibility issue is quite confusing.
See the following example.

X = "top-level"

class C
  X = "class-level"

  class << self
    def a
      puts X
    end
  end
end

def C.b
  puts X
end

class << C
  def c
    puts X
  end
end

C.a #=>class-level
C.b #=>top-level
C.c #=>top-level

class D
  X = "class-level"
  def f
    puts X
  end
end

obj = D.new

def obj.g
  puts X
end

class << obj
  def h
    puts X
  end
end

obj.f #=>class-level
obj.g #=>top-level
obj.h #=>class-level

Very inconsistent between a class and an object.
Can somebody explain this strange behavior?

Thanks.
Sam

···

On Thu, 2 Mar 2006, Minkoo Seo wrote:

The visibility issue is quite confusing.
See the following example.

X = "top-level"

class C
  X = "class-level"

  class << self
    def a
      puts X
    end
  end
end

def C.b
  puts X
end

class << C

  p [self, self.ancestors] #=> [#<Class:C>, [Class, Module, Object, Kernel]]

  def c
    puts X
  end
end

C.a #=>class-level
C.b #=>top-level
C.c #=>top-level

class D
  X = "class-level"
  def f
    puts X
  end
end

obj = D.new

def obj.g
  puts X
end

class << obj

  p [self, self.ancestors] #=> [#<Class:#<D:0xb7f3bda0>>, [D, Object, Kernel]]

  def h
    puts X
  end
end

obj.f #=>class-level
obj.g #=>top-level
obj.h #=>class-level

Very inconsistent between a class and an object.
Can somebody explain this strange behavior?

Well it's not inconsistent, it's just complicated :wink:

As you can see above for C.c the singleton class of C (#<Class:C>) is asked for the constant, it doesn't have C in it's ancestors, so the constant lookup finds Object's X.
For obj.h the singleton class of obj (#<Class:#<D:0xb7f3bda0>>) is asked for the constant, it does have D in it's ancestors, so D::X is found.

But actually it's even more complicated (continuing your code):

$obj=obj
class Object
  class << $obj
    def i
      puts X
    end
  end
end

obj.i #=>top-level

This is because the constant lookup first checks in all the outer lexical scopes if the constant is directly defined in one of the classes and then does a full const_get on the innermost class. So in this case, the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant X => no
2. Does Object (without ancestors) have a constant X => yes => constant found

If step 2 wouldn't have found the constant then ruby would have checked the ancestors of #<Class:#<D:0xb7f3bda0>> for the constant:

class D
  Y = "D::Y"
end

class Object
  class << $obj
    def j
      puts Y
    end
  end
end

obj.j #=>D::Y

Here the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant Y => no
2. Does Object (without ancestors) have a constant Y => no
3. Does #<Class:#<D:0xb7f3bda0>> (including ancestors) have a constant Y => yes => constant found

I hope that helps,
Dominik

···

On Sun, 05 Mar 2006 05:18:39 +0100, Sam Kong <sam.s.kong@gmail.com> wrote:

Hi --

But actually it's even more complicated (continuing your code):

$obj=obj
class Object
  class << $obj
    def i
      puts X
    end
  end
end

obj.i #=>top-level

This is because the constant lookup first checks in all the outer lexical scopes if the constant is directly defined in one of the classes and then does a full const_get on the innermost class. So in this case, the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant X => no
2. Does Object (without ancestors) have a constant X => yes => constant found

If step 2 wouldn't have found the constant then ruby would have checked the ancestors of #<Class:#<D:0xb7f3bda0>> for the constant:

class D
  Y = "D::Y"
end

class Object
  class << $obj
    def j
      puts Y
    end
  end
end

obj.j #=>D::Y

Here the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant Y => no
2. Does Object (without ancestors) have a constant Y => no
3. Does #<Class:#<D:0xb7f3bda0>> (including ancestors) have a constant Y => yes => constant found

But Object is always an ancestor, so you don't need step 2. Also,
step 2 (lookup in Object) doesn't really happen second; for example,
if you put yourself in D context, the lookup will hit D::X before it
hits Object::x:

$obj=obj
class Object
   class D
     class << $obj
       def k
         puts X
       end
     end
   end
end

obj.k # class-level

So the resolution path is:

   #<Class:#<D...>>
     D # X found here
      Object # X exists here but not reached

As I understand it, some of this is determined quasi-statically...
though not the singleton class parts, since those can't be determined
at all until runtime.

David

···

On Sun, 5 Mar 2006, Dominik Bathon wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black

Dominik Bathon wrote:

···

On Sun, 05 Mar 2006 05:18:39 +0100, Sam Kong <sam.s.kong@gmail.com> wrote:

> The visibility issue is quite confusing.
> See the following example.
>
> X = "top-level"
>
> class C
> X = "class-level"
>
> class << self
> def a
> puts X
> end
> end
> end
>
> def C.b
> puts X
> end
>
> class << C
  p [self, self.ancestors] #=> [#<Class:C>, [Class, Module, Object, Kernel]]
> def c
> puts X
> end
> end
>
> C.a #=>class-level
> C.b #=>top-level
> C.c #=>top-level
>
>
> class D
> X = "class-level"
> def f
> puts X
> end
> end
>
> obj = D.new
>
> def obj.g
> puts X
> end
>
> class << obj
  p [self, self.ancestors] #=> [#<Class:#<D:0xb7f3bda0>>, [D, Object,
Kernel]]
> def h
> puts X
> end
> end
>
> obj.f #=>class-level
> obj.g #=>top-level
> obj.h #=>class-level
>
> Very inconsistent between a class and an object.
> Can somebody explain this strange behavior?

Well it's not inconsistent, it's just complicated :wink:

As you can see above for C.c the singleton class of C (#<Class:C>) is
asked for the constant, it doesn't have C in it's ancestors, so the
constant lookup finds Object's X.
For obj.h the singleton class of obj (#<Class:#<D:0xb7f3bda0>>) is asked
for the constant, it does have D in it's ancestors, so D::X is found.

But actually it's even more complicated (continuing your code):

$obj=obj
class Object
  class << $obj
    def i
      puts X
    end
  end
end

obj.i #=>top-level

This is because the constant lookup first checks in all the outer lexical
scopes if the constant is directly defined in one of the classes and then
does a full const_get on the innermost class. So in this case, the
following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant X =>
no
2. Does Object (without ancestors) have a constant X => yes => constant
found

If step 2 wouldn't have found the constant then ruby would have checked
the ancestors of #<Class:#<D:0xb7f3bda0>> for the constant:

class D
  Y = "D::Y"
end

class Object
  class << $obj
    def j
      puts Y
    end
  end
end

obj.j #=>D::Y

Here the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant Y =>
no
2. Does Object (without ancestors) have a constant Y => no
3. Does #<Class:#<D:0xb7f3bda0>> (including ancestors) have a constant Y
=> yes => constant found

I hope that helps,

Yes. That helps a lot.
Thank you very much.

Sam

Hi --

class D
  Y = "D::Y"
end

class Object
  class << $obj
    def j
      puts Y
    end
  end
end

obj.j #=>D::Y

Here the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant Y => no
2. Does Object (without ancestors) have a constant Y => no
3. Does #<Class:#<D:0xb7f3bda0>> (including ancestors) have a constant Y => yes => constant found

But Object is always an ancestor, so you don't need step 2.

Yes, but these are the steps that ruby (1.8.4) does when looking up the constants, here is the code (eval.c):

static VALUE
ev_const_get(cref, id, self)
     NODE *cref;
     ID id;
     VALUE self;
{
     NODE *cbase = cref;
     VALUE result;

     while (cbase && cbase->nd_next) {
  VALUE klass = cbase->nd_clss;

  if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id);
  while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
      if (result == Qundef) {
    if (!RTEST(rb_autoload_load(klass, id))) break;
    continue;
      }
      return result;
  }
  cbase = cbase->nd_next;
     }
     return rb_const_get(cref->nd_clss, id);
}

The while loop checks if the constant is defined directly (without ancestors) in one of the enclosing classes, and finally if the while loop doesn't find the constant ruby does a full rb_const_get() on the innermost class (which includes the ancestors).

Also,
step 2 (lookup in Object) doesn't really happen second; for example,
if you put yourself in D context, the lookup will hit D::X before it
hits Object::x:

$obj=obj
class Object
   class D
     class << $obj
       def k
         puts X
       end
     end
   end
end

obj.k # class-level

So the resolution path is:

   #<Class:#<D...>>
     D # X found here
      Object # X exists here but not reached

In this case yes, but that doesn't contradict what I said.

As I understand it, some of this is determined quasi-statically...
though not the singleton class parts, since those can't be determined
at all until runtime.

You can think of it as happening "quasi-statically", but actually class, module and "class <<" are executed almost identically by the interpreter (only different "preparations").

Dominik

···

On Sun, 05 Mar 2006 20:01:49 +0100, <dblack@wobblini.net> wrote:

On Sun, 5 Mar 2006, Dominik Bathon wrote:

Hi --

Hi --

class D
  Y = "D::Y"
end

class Object
  class << $obj
    def j
      puts Y
    end
  end
end

obj.j #=>D::Y

Here the following happens:

1. Does #<Class:#<D:0xb7f3bda0>> (without ancestors) have a constant Y => no
2. Does Object (without ancestors) have a constant Y => no
3. Does #<Class:#<D:0xb7f3bda0>> (including ancestors) have a constant Y => yes => constant found

But Object is always an ancestor, so you don't need step 2.

Yes, but these are the steps that ruby (1.8.4) does when looking up the constants, here is the code (eval.c):

static VALUE
ev_const_get(cref, id, self)
  NODE *cref;
  ID id;
  VALUE self;
{
  NODE *cbase = cref;
  VALUE result;

  while (cbase && cbase->nd_next) {
  VALUE klass = cbase->nd_clss;

  if (NIL_P(klass)) return rb_const_get(CLASS_OF(self), id);
  while (RCLASS(klass)->iv_tbl && st_lookup(RCLASS(klass)->iv_tbl, id, &result)) {
      if (result == Qundef) {
    if (!RTEST(rb_autoload_load(klass, id))) break;
    continue;
      }
      return result;
  }
  cbase = cbase->nd_next;
  }
  return rb_const_get(cref->nd_clss, id);
}

The while loop checks if the constant is defined directly (without ancestors) in one of the enclosing classes, and finally if the while loop doesn't find the constant ruby does a full rb_const_get() on the innermost class (which includes the ancestors).

I think I was misunderstanding the relation between your example and
your explanation. If I'm (now) right, you were just using Object as
an example of an enclosing class. I had thought you were saying that
Object itself always gets checked before the ancestors.

As I understand it, some of this is determined quasi-statically...
though not the singleton class parts, since those can't be determined
at all until runtime.

You can think of it as happening "quasi-statically", but actually class, module and "class <<" are executed almost identically by the interpreter (only different "preparations").

I mean constant resolution specifically. But I may be behind the
times.

David

···

On Mon, 6 Mar 2006, Dominik Bathon wrote:

On Sun, 05 Mar 2006 20:01:49 +0100, <dblack@wobblini.net> wrote:

On Sun, 5 Mar 2006, Dominik Bathon wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

I think I was misunderstanding the relation between your example and
your explanation. If I'm (now) right, you were just using Object as
an example of an enclosing class. I had thought you were saying that
Object itself always gets checked before the ancestors.

I used Object because the top-level X is stored in Object and I wanted to show that there is a (maybe surprising) difference between:

class << obj
  def h
    puts X
  end
end

and

$obj=obj
class Object
  class << $obj
    def i
      puts X
    end
  end
end

···

On Sun, 05 Mar 2006 21:15:09 +0100, <dblack@wobblini.net> wrote:

As I understand it, some of this is determined quasi-statically...
though not the singleton class parts, since those can't be determined
at all until runtime.

You can think of it as happening "quasi-statically", but actually class, module and "class <<" are executed almost identically by the interpreter (only different "preparations").

I mean constant resolution specifically. But I may be behind the
times.

David