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

> Hi --
>
> On Sun, 5 Mar 2006, Dominik Bathon wrote:
>
>> 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