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