[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Class method in singleton_methods?

minkoo.seo@gmail.com

3/2/2006 4:39:00 AM

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

7 Answers

dblack

3/2/2006 2:07:00 PM

0

dblack

3/2/2006 2:14:00 PM

0

Sam Kong

3/5/2006 4:15:00 AM

0


dblack@wobblini.net wrote:
> Hi --
>
> On Thu, 2 Mar 2006, Minkoo Seo wrote:
>
> > 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

Dominik Bathon

3/5/2006 2:15:00 PM

0

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

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


dblack

3/5/2006 7:02:00 PM

0

Dominik Bathon

3/5/2006 9:37:00 PM

0

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

> 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

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




Sam Kong

3/6/2006 8:57:00 PM

0


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