Want to see a really amazing error I got this week? Okay… but to
make it more interesting I am going to the change some names to
protect the innocent, and offer up a little challenge: How can
reproduce it?
The error is this:
uninitialized constant X::Foo::X (NameError)
Did you catch that?
Think you can solve it?
I imagine your mind is getting a bit mushy about now 
throw NameError.new(“uninitialized constant X::Foo::X”)
This is a pretty trivial error to generate. Just reference the
constant that doesn’t exist:
$ irb
ruby-1.9.2-p180 :001 > module X; module Foo; end; end
=> nil
ruby-1.9.2-p180 :002 > X::Foo::X
NameError: uninitialized constant X::Foo::X
~ jf
John F.
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: User John Feminella - Stack Overflow
On Jun 8, 9:20am, John F. [email protected] wrote:
This is a pretty trivial error to generate. Just reference the
constant that doesn’t exist:
$ irb
ruby-1.9.2-p180 :001 > module X; module Foo; end; end
=> nil
ruby-1.9.2-p180 :002 > X::Foo::X
NameError: uninitialized constant X::Foo::X
Ah good point. I made an assumption. A qualifier then: X does exist.
How about this must be as top of your solution.
module X; end
On Wed, Jun 8, 2011 at 6:43 AM, Intransition [email protected]
wrote:
NameError: uninitialized constant X::Foo::X
Ah good point. I made an assumption. A qualifier then: X does exist.
How about this must be as top of your solution.
module X; end
The top-level X (and the Foo underneath it) seems required to get the
error, so that doesn’t make it harder. If you reference X::Foo::X
without X existing, you’ll get
uninitialized constant Object::X (NameError)
If you reference X::Foo::X with just the part you have above, you’ll
get uninitialized constant X::Foo (NameError)
The easiest way to get the error you ask about is
module X; module Foo; end; end
X::Foo::X
But I would guess that that probably isn’t what you are looking for
either.
On Wed, Jun 8, 2011 at 6:16 AM, Steve K. [email protected]
wrote:
throw NameError.new(“uninitialized constant X::Foo::X”)
Doesn’t give the right result. You want raise, not throw.
On Jun 8, 9:16am, Steve K. [email protected] wrote:
throw NameError.new(“uninitialized constant X::Foo::X”)
Oh you are a clever one 
On Jun 8, 2011, at 10:56 AM, Christopher D. wrote:
The easiest way to get the error you ask about is
module X; module Foo; end; end
X::Foo::X
But I would guess that that probably isn’t what you are looking for either.
It wouldn’t be, because that’s not an error: it ends up referencing the
top-level X from inside Foo, giving this warning:
(irb):1407: warning: toplevel constant X referenced by X::Foo::X
Michael E.
[email protected]
http://carboni.ca/
On Jun 8, 10:56am, Christopher D. [email protected] wrote:
module X; module Foo; end; end
X::Foo::X
Well, Balls. That in itself seems ridiculous, but you are right. I’m
not sure why it raises that though. Maybe the code is silly, but is it
really wrong? Try X::Foo.const_get(:X) and it works fine. Seems
inconsistent, doesn’t it?
But I would guess that that probably isn’t what you are looking for either.
Yes, in the actual code X is being referenced from within Foo but is
not fully qualified.
On Jun 8, 10:59am, Michael E. [email protected] wrote:
(irb):1407: warning: toplevel constant X referenced by X::Foo::X
Interesting. What platform on you on?
Thomas S. wrote in post #1003914:
Think you can solve it?
Here’s one way:
$ irb --simple-prompt
module X
module Foo
self::X
end
end
NameError: uninitialized constant X::Foo::X
from (irb):3
from :0
This is more sensible than it might appear at first. I use self::X
frequently when I want dynamic scope resolution (e.g. use the constant
which belongs to a subclass, rather than the parent class)
On Jun 8, 11:28am, Intransition [email protected] wrote:
Interesting. What platform on you on?
s/on/are/
I’ve always been pretty bad with the typos, but I swear this week I’ve
gone into dyslexic overdrive. My apologies.
On Jun 8, 2011, at 11:28 AM, Intransition wrote:
It wouldn’t be, because that’s not an error: it ends up referencing the
top-level X from inside Foo, giving this warning:
(irb):1407: warning: toplevel constant X referenced by X::Foo::X
Interesting. What platform on you on?
That was on 1.9.2p188. Seems to be a change in 1.9 - I started checking
against other RVM installs
after seeing your response that X::Foo::X gives an error. I could’ve
sworn I understood the differences
in constant resolution between 1.9.2 and 1.8.7… back to the drawing
board there, I guess.
In fact, I can’t even produce that error in 1.9.2.
Michael E.
[email protected]
http://carboni.ca/
On Thu, Jun 09, 2011 at 12:39:56AM +0900, Michael E. wrote:
That was on 1.9.2p188. Seems to be a change in 1.9 - I started checking
against other RVM installs after seeing your response that X::Foo::X
gives an error. I could’ve sworn I understood the differences in
constant resolution between 1.9.2 and 1.8.7… back to the drawing
board there, I guess.
In fact, I can’t even produce that error in 1.9.2.
It works the same both 1.8.7, 1.9.1, and 1.9.2 for me.
On Jun 8, 2011, at 12:19 PM, Chad P. wrote:
It works the same both 1.8.7, 1.9.1, and 1.9.2 for me.
–
Chad P. [ original content licensed OWL: http://owl.apotheon.org ]
… and my contribution becomes meaningless. Ugh. I closed my irb
session and re-opened
it, and now can’t repro the top-level dereference. If I can, I’ll post,
but I’m guessing I should
have just used a fresh session instead one that appears to have been
1500 evaluations deep.
Sorry for the confusion/noise,
Michael E.
[email protected]
http://carboni.ca/
On Wed, Jun 8, 2011 at 7:59 AM, Michael E. [email protected] wrote:
On Wed, Jun 8, 2011 at 8:27 AM, Intransition [email protected]
wrote:
The easiest way to get the error you ask about is
module X; module Foo; end; end
X::Foo::X
Well, Balls. That in itself seems ridiculous, but you are right. I’m
not sure why it raises that though. Maybe the code is silly, but is it
really wrong? Try X::Foo.const_get(:X) and it works fine. Seems
inconsistent, doesn’t it?
Not really. I’d expect X::Foo::X to get the constant at that path
(which doesn’t exist, hence the error), while X::Foo.const_get(:X) I’d
expect to resolve as if X was referenced within X::Foo, including
climbing up the chain, and to return the top-level X.
But I would guess that that probably isn’t what you are looking for
either.
Yes, in the actual code X is being referenced from within Foo but is
not fully qualified.
I could swear that I have run into that error in some things in the
past (and resolved it by fully qualifying the affected references),
but now I can’t figure out how to reproduce it.
Christopher D. wrote in post #1004068:
X::Foo.const_get(:X) I’d
expect to resolve as if X was referenced within X::Foo, including
climbing up the chain, and to return the top-level X.
That’s a pain, I have in the past used modules to limit access to only a
predefined set of things:
module Safe
module Foo; end
module Bar; end
end
dirty = “Foo”
m = Safe.const_get(dirty) # ok
dirty = “Object”
m = Safe.const_get(dirty) # I wanted this to fail
I guess you need to build an explicit Hash.
Yes, in the actual code X is being referenced from within Foo but is
not fully qualified.
Is it partially qualified, or a completely bare ‘X’?
Partially qualified is easy to reproduce:
module X; module Foo; Foo::X; end; end
NameError: uninitialized constant X::Foo::X
from (irb):1
from :0
Note there is a subtle difference with the following:
module X::Foo; Foo::X; end
NameError: uninitialized constant X::Foo::Foo
from (irb):4
from :0
I don’t think that’s the issue here, but I was once caught out by the
difference between
module A; module B; …; end; end
and
module A::B; …; end
I think the problem which bit me was this:
module X
module A; end
module B; end
end
=> nil
module X; module A; B; end; end
=> X::B
module X::A; B; end
NameError: uninitialized constant X:
:B
from (irb):6
But it’s not the same as reported in this thread:
module X::A; X; end
=> X
I thought constant lookups would always try in the top-level scope, so I
can’t see how a bare “X” would fail. OTOH, I don’t think I’ve ever seen
any authoritative documentation of the constant lookup rules.
I think the issue which bit me was this:
module Foo
module X
p X # works
end
end
module Foo::X
p X # uninitialized constant Foo:
:X
end
But that’s not the same as reported here. I thought constant lookups
should always try in the top-level scope, so I can’t see how a bare “X”
would fail if there exists a top-level module “X”.
OTOH, I don’t think I’ve ever seen any authoritative documentation of
the constant lookup rules.