[ruby-core:32675] Re: warning: toplevel constant XX referenced by YY::XX

From: Steven Parkes <smparkes@...>
Date: 2010-10-02 22:21:21 UTC
List: ruby-core #32675
This is a huge blast from the past (c.f. http://bit.ly/9VSaM7).

I'm wondering if we could make this into a hard (i.e., call const_missing) error rather than the hard-printed/otherwise undetectable warning it is right now?

This is kicking my butt in Rails right now. Basically, if a top level constant (probably any constant found in the lookup chain) is created that aliases a nested class/module that Rails wants to autoload using its const_missing callback, you get the warning message and Rails never gets a const_missing call (and you get the global constant, which isn't what's desired).

(I think) I'd argue that the current behavior is scary given that the introduction of a new constant at the root level can change the behavior of existing explicitly namespaced code. Granted, I think this is only if you do const_missing-based loading.

I don't know if much existing code relies on this? If there's code that does, the workaround seems fairly simple, by defining a constant at the scoped level that points to the value at the other level (though that might have const_missing/autoload ramifications ...)

I haven't really found a workaround for the other way around since the current behavior isn't catchable. I actually hacked my code to define a function of the same name as the constant. The function looks in constants to determine if the nested constant is loaded. Then I use Foo.Bar in client code in place of Foo::Bar where the reference is needed. Yuck. 

The seemingly trivial (but not expert) patch is to change

	    if (value == Qundef) {

to

            if (value == Qundef ||
                (exclude && tmp == rb_cObject && klass != rb_cObject)) {


in rb_const_get_0, along with removing the next conditional which is now dead.

I'd use autoload to work around this, but that's kicking my butt, too. There doesn't seem any way to reset the autoload state of a symbol/file? (I think) Rails unloads both the autoload caller/container and target, but then there doesn't seem anyway to get ruby to reengage autoload for that symbol/file again? Rails reloads the container which has the autoload calls in it and autoload gets called again, but those will never fire again (even though the symbol referenced doesn't exist).

In This Thread

Prev Next