A little challenge - reproduce this error

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 :wink:

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 :wink:

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::a::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::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.