a little challenge - reproduce this error

I

Intransition

I bet a few people have come across it without fully knowing what was
going on and just fixed their issue by adding `::` to the "X". That's
what I did a few times before I realized what the hell was going on.

The change needed to cause the error is this:

=A0 =A0 module X
=A0 =A0 =A0 class Foo < BasicObject
=A0 =A0 =A0 =A0 def call
=A0 =A0 =A0 =A0 =A0 X
=A0 =A0 =A0 =A0 end
=A0 =A0 =A0 end
=A0 =A0 end

Right off you can see this only effect Ruby 1.9+ (b/c 1.8 has no
BasicObject).

Next up... why it happens and how to fix.

Ok, so the fix to this problem is... #const_missing:

=A0 =A0 module X
=A0 =A0 =A0 class Foo < BasicObject
=A0 =A0 =A0 =A0 def call
=A0 =A0 =A0 =A0 =A0 X
=A0 =A0 =A0 =A0 end
def self.const_missing(const)
Object.const_get(const)
end
=A0 =A0 =A0 end
=A0 =A0 end

Which tells us why we get the error in the first place. Toplevel
constants, like toplevel instance methods, are defined on Object
itself -- the toplevel (aka `main`) is (mostly) just a proxy for
Object. And since BasicObject doesn't inherit from Object like every
other object in Ruby's universe, it can't find, in this case, module
X.

So that's the deal. If you ever run into this, you now know what to
do.

SIDE NOTE: I'm pretty sure that toplevel should not be a proxy of
object. And that constant look up should terminate with the toplevel
(just after Object) rather than with the Object class. A big benefit
from this would be the ability eval scripts at the toplevel instead of
in a protected module that emulated the toplevel (yet another proxy)
in order to prevent method definitions from polluting every object. I
mean think about that --every object. Talk about your monkey patching!
I've mentioned this to matz before, and while he's never said as much,
i'm hopeful that Ruby 2.0 (whenever that might arrive) will take the
idea to heart.

P.S. In my attempt to "quizify" this Ruby quirk, I have to say, James
Edward Gray II, I am humbled! :)
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

Ok, so the fix to this problem is... #const_missing:

module X
class Foo < BasicObject
def call
X
end
def self.const_missing(const)
Object.const_get(const)
end
end
end

Which tells us why we get the error in the first place. Toplevel
constants, like toplevel instance methods, are defined on Object
itself -- the toplevel (aka `main`) is (mostly) just a proxy for
Object. And since BasicObject doesn't inherit from Object like every
other object in Ruby's universe, it can't find, in this case, module
X.

So that's the deal. If you ever run into this, you now know what to
do.
Fascinating stuff!


SIDE NOTE: I'm pretty sure that toplevel should not be a proxy of
object. And that constant look up should terminate with the toplevel
(just after Object) rather than with the Object class. A big benefit
from this would be the ability eval scripts at the toplevel instead of
in a protected module that emulated the toplevel (yet another proxy)
in order to prevent method definitions from polluting every object. I
mean think about that --every object. Talk about your monkey patching!
I've mentioned this to matz before, and while he's never said as much,
i'm hopeful that Ruby 2.0 (whenever that might arrive) will take the
idea to heart.
I could see that. I already avoid defining toplevel methods, but when I do
make them, I usually make them on main's singleton class (unless, of course,
it really does need to be globally callable).

P.S. In my attempt to "quizify" this Ruby quirk, I have to say, James
Edward Gray II, I am humbled! :)
lol.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,104
Messages
2,570,643
Members
47,247
Latest member
youngcoin

Latest Threads

Top