Ruby 1.9.2 Constant Lookup with BasicObject

ruby-1.9.2-p0 > module M
ruby-1.9.2-p0 ?> end
=> nil
ruby-1.9.2-p0 > class X < BasicObject
ruby-1.9.2-p0 ?> include M
ruby-1.9.2-p0 ?> end
NameError: uninitialized constant X::M
  from (irb):4:in `<class:X>'
  from (irb):3
  from /home/trans/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

module M is defined inside Object space.
X is one level above it - it is inside BasicObject( where no Object space is visible)
Inside X you try to include an object from other space (one level below)
I think it will work if you include Object::M

···

On 08/30/2010 07:47 PM, Intransition wrote:

ruby-1.9.2-p0> module M
ruby-1.9.2-p0 ?> end
  => nil
ruby-1.9.2-p0> class X< BasicObject
ruby-1.9.2-p0 ?> include M
ruby-1.9.2-p0 ?> end
NameError: uninitialized constant X::M
  from (irb):4:in `<class:X>'
  from (irb):3
  from /home/trans/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

I filed a bug report on Ruby's issue tracker and matz brought up the
same. Here's my take:

I see the technical reason it occurs, but to accept that as proper
behavior is going to hobble the usefulness of BasicObject.

First of all, it means one's ability to open a class and modify it
will be conditional. One will have to check if it is a BasicObject
upfront. That's easy to do if you're working with one class you
already know, but consider how it effects doing some meta-programming
where code is injected into any arbitrary class.

Worst still is that it makes importing code into a namespace very
fragile. Consider the simplistic example of having some code in a
script to eval into a module.

  module M
    eval(File.read('file.rb'))
  end

If file.rb contains:

  class R
  end

  class Q < BasicObject
    def r; R.new; end
  end

Then it will break whether we use R or ::R.

I feel the underlying issue here goes back to some other issues we've
discussed some years ago about the top-level. Routing the toplevel to
Object is not as flexible or robust as having a toplevel be an
independent self-extended module in which constant resolution would
terminate.

···

On Aug 31, 8:50 am, Eugen Ciur <eu...@prime-tel.com> wrote:

module M is defined inside Object space.
X is one level above it - it is inside BasicObject( where no Object
space is visible)
Inside X you try to include an object from other space (one level below)
I think it will work if you include Object::M

On 08/30/2010 07:47 PM, Intransition wrote:

> ruby-1.9.2-p0> module M
> ruby-1.9.2-p0 ?> end
> => nil
> ruby-1.9.2-p0> class X< BasicObject
> ruby-1.9.2-p0 ?> include M
> ruby-1.9.2-p0 ?> end
> NameError: uninitialized constant X::M
> from (irb):4:in `<class:X>'
> from (irb):3
> from /home/trans/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

Hi,

I understand your complain. But the solution should be concrete, and
hopefully consistent with other parts of the language. I am not sure
your "a toplevel being an independent self-extended module" proposal
is the way to go (yet).

              matz.

···

In message "Re: Ruby 1.9.2 Constant Lookup with BasicObject" on Tue, 31 Aug 2010 23:23:53 +0900, Intransition <transfire@gmail.com> writes:

On Aug 31, 8:50 am, Eugen Ciur <eu...@prime-tel.com> wrote:

module M is defined inside Object space.
X is one level above it - it is inside BasicObject( where no Object
space is visible)
Inside X you try to include an object from other space (one level below)
I think it will work if you include Object::M

On 08/30/2010 07:47 PM, Intransition wrote:

> ruby-1.9.2-p0> module M
> ruby-1.9.2-p0 ?> end
> => nil
> ruby-1.9.2-p0> class X< BasicObject
> ruby-1.9.2-p0 ?> include M
> ruby-1.9.2-p0 ?> end
> NameError: uninitialized constant X::M
> from (irb):4:in `<class:X>'
> from (irb):3
> from /home/trans/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

I filed a bug report on Ruby's issue tracker and matz brought up the
same. Here's my take:

I see the technical reason it occurs, but to accept that as proper
behavior is going to hobble the usefulness of BasicObject.

First of all, it means one's ability to open a class and modify it
will be conditional. One will have to check if it is a BasicObject
upfront. That's easy to do if you're working with one class you
already know, but consider how it effects doing some meta-programming
where code is injected into any arbitrary class.

Worst still is that it makes importing code into a namespace very
fragile. Consider the simplistic example of having some code in a
script to eval into a module.

module M
   eval(File.read('file.rb'))
end

If file.rb contains:

class R
end

class Q < BasicObject
   def r; R.new; end
end

Then it will break whether we use R or ::R.

I feel the underlying issue here goes back to some other issues we've
discussed some years ago about the top-level. Routing the toplevel to
Object is not as flexible or robust as having a toplevel be an
independent self-extended module in which constant resolution would
terminate.

The rules of constant name resolution have changed with BasicObject.
There was a step before that said that if nesting and ancestors didn't
find it, you checked Object.

I'd like to know the current complete algorithm, including const_missing calls.

After some trial and error it seems the algorithm is the same as in
1.8 if we take into account that the special rule that checks Object
as a last resort applies only to modules.