Amazing behavior of include module

Hi,
I do not understand how is following code working:
irb(main):001:0> module AAA
irb(main):002:1> class BBB
irb(main):003:2> end
irb(main):004:1> end
=> nil
irb(main):005:0> BBB::BBB
NameError: uninitialized constant BBB
from (irb):5
from /usr/local/bin/irb:12:in <main>' irb(main):006:0> AAA::BBB::BBB NameError: uninitialized constant AAA::BBB::BBB from (irb):6 from /usr/local/bin/irb:12:in
irb(main):007:0> include AAA
=> Object
irb(main):008:0> BBB::BBB
=> AAA::BBB
irb(main):009:0> BBB::BBB::BBB
=> AAA::BBB
irb(main):010:0> BBB::BBB::BBB::BBB
=> AAA::BBB
irb(main):011:0> AAA::BBB::BBB::BBB
=> AAA::BBB

I thought that last four lines will not work, but they do. How is it
possible?
Thank you.
Pavel Strnad

This is really quite odd to me. Especially since AAA::BBB.constants
returns
an empty array. Anybody have an answer to this?

On Wed, Feb 2, 2011 at 11:15 PM, Andrew W.
[email protected]wrote:

irb(main):003:2> end
irb(main):007:0> include AAA

I thought that last four lines will not work, but they do. How is it
possible?
Thank you.
Pavel Strnad

Including AAA at the top level, as in line 7, acts the same as including
it
on Object, so every object suddenly has BBB available to it.

module A; class B; end; end
include A
Object::A
Fixnum::A
class X; end
X::A
X.ancestors # => [X, Object, A, Kernel, BasicObject]

On Wed, Feb 2, 2011 at 10:49 AM, Pavel Strnad
[email protected]wrote:

   from /usr/local/bin/irb:12:in `<main>'

irb(main):010:0> BBB::BBB::BBB::BBB
=> AAA::BBB
irb(main):011:0> AAA::BBB::BBB::BBB
=> AAA::BBB

I thought that last four lines will not work, but they do. How is it
possible?
Thank you.
Pavel Strnad

The short answer is:

module A
class B
end
end
Object.ancestors # => [Object, Kernel, BasicObject]
include A
Object.ancestors # => [Object, A, Kernel, BasicObject]

What you should do to fix this is use extend rather than include:

module A
class B
end
end

extend A
begin
B # => A::B
Fixnum::B # =>
rescue
$! # => #<NameError: uninitialized constant Fixnum::B>
end

include A
begin
B # => A::B
Fixnum::B # => A::B
rescue
$! # =>
end

I made a post about it a while back, though I was talking about this
problem
with methods rather than classes
http://groups.google.com/group/ruby-talk-google/browse_thread/thread/e33422848e168c4e?fwc=2

Including AAA at the top level, as in line 7, acts the same as including it
on Object, so every object suddenly has BBB available to it.

This explanation makes sense, and certainly fits the facts. But why is
doing
‘include’ from an irb prompt the same as including the module in Object?
If
self points to main, and main is an instance of Object, shouldn’t the
module
get included into main’s eigenclass?

I’m actually working on a static analysis tool that came up against the
issue
of modeling Ruby’s inclusion semantics recently. The top-level object
has
a couple of special behaviors, designed to bring a few of the features
of
classes to the top-level in a (hopefully) more intuitive way. If you
run:

ruby -e ‘p methods(false)’

You’ll get:

[:to_s, :public, :private, :include]

to_s just returns “main”, and public and private bring visibility to
top-level code.
Include is defined (for 1.9.2) at vm.c:968:

static VALUE
top_include(int argc, VALUE *argv, VALUE self)
{
rb_thread_t *th = GET_THREAD();

rb_secure(4);
if (th->top_wrapper) {

rb_warning
(“main#include in the wrapped load is effective only in wrapper
module”);
return rb_mod_include(argc, argv, th->top_wrapper);
}
return rb_mod_include(argc, argv, rb_cObject);
}

The most important line being the most common one, the final one: it
simply includes
the given modules into the Object class.

I haven’t thought too hard about what the ramifications would be if it
were instead
included into the main object’s eigenclass, so this answer might not be
too satisfying,
but well, there it is.

Cheers,
Mike Edgar
http://carboni.ca/

On Thu, Feb 3, 2011 at 5:01 AM, Andrew W. [email protected]
wrote:

Including AAA at the top level, as in line 7, acts the same as including it
on Object, so every object suddenly has BBB available to it.

This explanation makes sense, and certainly fits the facts. But why is doing
‘include’ from an irb prompt the same as including the module in Object? If
self points to main, and main is an instance of Object, shouldn’t the module
get included into main’s eigenclass?

I believe IRB mimics behavior of the Ruby interpreter here:

10:44:58 ~$ ruby19 <<CODE

module A; class B; end; end
include A
p B
p Fixnum::B
CODE
A::B
A::B
10:45:32 ~$ ruby19 -e ‘p self’
main
10:45:51 ~$ irb19
Ruby version 1.9.2
irb(main):001:0> self
=> main

Reasoning behind this is certainly is that this way namespaces work as
expected. If only main would get access to the inclusion, you could
not use a constant nested in your included module in any other
class.

Personally I don’t like including at top level that much because it
always includes the risk of name clashes. I usually do this only in
small or one off scripts.

Kind regards

robert