From: Sam Kong Date: 2006-03-07T05:58:40+09:00 Subject: Re: Class method in singleton_methods? Dominik Bathon wrote: > On Sun, 05 Mar 2006 05:18:39 +0100, Sam Kong 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, 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] #=> [#>, [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 (#) 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 (#>) 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 #> (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 #> 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 #> (without ancestors) have a constant Y => > no > 2. Does Object (without ancestors) have a constant Y => no > 3. Does #> (including ancestors) have a constant Y > => yes => constant found > > > I hope that helps, Yes. That helps a lot. Thank you very much. Sam