Dominik Bathon
3/5/2006 2:15:00 PM
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