Confusion with constant look up

Hi,

Can anyone tell me why the below code failed?

class A
  module B; end
end

class C < A
  class D
    B
  end
end
# NameError: uninitialized constant C::D::B

···

--
Posted via http://www.ruby-forum.com/.

Hi,

Can anyone tell me why the below code failed?

class A
  module B; end
end

class C < A
  class D
    B # line L
  end
end
# NameError: uninitialized constant C::D::B

an ancestor of the enclosing class C::D.

Note that when Ruby checks the nesting, it looks up the constants stored in
the very class or module objects, their ancestors are not inspected.

···

On Sun, Sep 29, 2013 at 12:45 AM, Love U Ruby <lists@ruby-forum.com> wrote:
A::B is a constant of A, but A is not in the nesting in line L, nor it is

Code A:

module A
  module B; end
end

module A::C
  p Module.nesting
end
# >> [A::C]

Code B:

module A
  module B; end
end

module A
  module C
    p Module.nesting
  end
end
# >> [A::C, A]

Why code A and B doesn't give the same result?

···

--
Posted via http://www.ruby-forum.com/.

Xavier Noria wrote in post #1122778:

···

On Sun, Sep 29, 2013 at 12:45 AM, Love U Ruby <lists@ruby-forum.com> > wrote:

Note that when Ruby checks the nesting, it looks up the constants stored
in
the very class or module objects, their ancestors are not inspected.

Does Ruby has any constant look up rules,like method look ups?

--
Posted via http://www.ruby-forum.com/\.

Code A:

module A
  module B; end
end

module A::C
  p Module.nesting
end
# >> [A::C]

Code B:

module A
  module B; end
end

module A
  module C
    p Module.nesting
  end
end
# >> [A::C, A]

Why code A and B doesn't give the same result?

Because nesting is a stack that is manipulated by the class and module
keywords (and some obscure use cases of the *_eval family).

The module keywords above push **the module object** to the stack. Note
that I said the module object, nesting has nothing to do with constants. In
Code A you push only one module object to the nesting, the one called
"A::C". In code B there are two pushes, first you push the module object
called "A", and then the one called "A::C:".

The talk I linked to also covers that a little bit, since you are
interested in this I really recommend that you watch it, it will bring you
up to speed with the main ideas in place.

···

On Sun, Sep 29, 2013 at 8:43 AM, Love U Ruby <lists@ruby-forum.com> wrote:

Xavier Noria wrote in post #1122778:

···

On Sun, Sep 29, 2013 at 1:15 AM, Love U Ruby <lists@ruby-forum.com> wrote:

> On Sun, Sep 29, 2013 at 12:45 AM, Love U Ruby <lists@ruby-forum.com> > > wrote:
>

>
> Note that when Ruby checks the nesting, it looks up the constants stored
> in
> the very class or module objects, their ancestors are not inspected.

Does Ruby has any constant look up rules,like method look ups?

Yes, please have a look at the first 15 mins of this talk:

  http://www.youtube.com/watch?v=8lYR9WxIRH0

The algorithms are actually a bit more complicated because Kernel#autoload
may define constants to be loaded lazily and the interpreter checks if what
is looking for was declared to be autoloaded in every step. There's also
const_missing. But anyway, you'll get the idea.

Xavier Noria wrote in post #1122791:

(and some obscure use cases of the *_eval family).

Can you one or two examples to understand the above sentence? I don't
understand what do you mean?

The module keywords above push **the module object** to the stack. Note
that I said the module object, nesting has nothing to do with constants.
In

So when we use `class` keyword then also it is pushed to the Stack like
module objects. Am I right ?

···

--
Posted via http://www.ruby-forum.com/\.

Xavier Noria wrote in post #1122790:

Xavier Noria wrote in post #1122778:

Yes, please have a look at the first 15 mins of this talk:

  http://www.youtube.com/watch?v=8lYR9WxIRH0

I am also downloading this - https://www.youtube.com/watch?v=wCyTRdtKm98

I enjoyed the talk.. Although I need to watch 2 more times the previous
one. I have one question to you. Did you write any blog on the same
topic. I am asking this because,the algorithm you were talking about
there,is the one I need to understand first. I was checking if you write
anwhere in the internet that algorithm. If so could you give me the
link? If I get a chance to see the drafted algorithm,I can see that and
try some examples in my IRB looking at your algorithm..

Thanks,

···

On Sun, Sep 29, 2013 at 1:15 AM, Love U Ruby <lists@ruby-forum.com> > wrote:

--
Posted via http://www.ruby-forum.com/\.

Xavier Noria wrote in post #1122791:

(and some obscure use cases of the *_eval family).

Can you one or two examples to understand the above sentence? I don't
understand what do you mean?

Sure.

Blocks do not change nesting, in particular when passed to *_eval
invocations. For example:

    class C
    end

    C.class_eval do
      # nesting unchanged, , does NOT include C
    end

But *_eval accept strings, in that case nesting is modified in the context
of the eval'ed code

    class C
    end

    C.class_eval "p Module.nesting" # prints [C]
    p Module.nesting # prints

(Note: class_eval BLOCK changed nesting in some versions of 1.9.1 IIRC, but
the change was discarded.)

> The module keywords above push **the module object** to the stack. Note

> that I said the module object, nesting has nothing to do with constants.
> In

So when we use `class` keyword then also it is pushed to the Stack like
module objects. Am I right ?

Yes:

    class C
      p Module.nesting # prints [C]

      class << self
        p Module.nesting # prints [#<Class:C>, C]
      end
    end

Xavier

···

On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby <lists@ruby-forum.com> wrote:

I enjoyed the talk.. Although I need to watch 2 more times the previous

one. I have one question to you. Did you write any blog on the same
topic.

Not really. I'd like to write a little book about constants in Ruby, since
it such a fundamental topic, not very well understood in my experience, and
even less documented. Maybe someday.

"The Ruby Programming Language" has a section about constant lookup, but it
does not mention autoloaded constants (via Kernel#autoload, not related to
Rails autoloading, see below).

I am asking this because,the algorithm you were talking about
there,is the one I need to understand first. I was checking if you write
anwhere in the internet that algorithm. If so could you give me the
link? If I get a chance to see the drafted algorithm,I can see that and
try some examples in my IRB looking at your algorithm..

Evaluation of relative constants works this way (assignments are
different). Let's imagine we are resolving X in

    module A::B
      include M

      class C::smiley: < E::F
        include N

         X
      end
    end

1. Check the nesting, from the most inner scope to the most outer scope.
That is, C::smiley: first, then A::B. It is important to highlight that Object
does NOT belong to the nesting. In each element of the nesting, check if
the constant belongs to the class or module itself, ignoring ancestors. In
particular, in (1) the algorithm totally ignores N, E::F, and M. It really
only looks up in the constant tables of C::smiley: and A::B.

Let's suppose it was not found.

2. Inspect the ancestors of the enclosing class or module. In the example
N, E::F, Object, Kernel, BasicObject in that order (assumes >= 1.9 and that
E::F inherits from Object).

Let's suppose it was not found.

3. If the enclosing class or module is a module, check Object explicitly,
by hand. That is not the case in the example.

Let's suppose it was not found.

4. Call const_missing if implemented (this is a method lookup, could be
inherited).

Let's suppose it was not found.

5. Raise NameError.

Also, in (1)--(3) every time the interpreter checks for the constant in
some particular class or module and fails, it still checks if there is a
Kernel#autoload for it before going on.

Xavier

PS: "nesting" reminds undefined, and has some obscure cases, but you get
the idea in the ordinary situation, and Module.nesting can tell.

···

On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby <lists@ruby-forum.com> wrote:

Xavier Noria wrote in post #1122972:

···

On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby <lists@ruby-forum.com> > wrote:

Module::nesting I understood..But I am bit confused with
Module::nesting,Module::constants and Module#constants --- What are the
use cases(nesting I know,helps to look up constants) ? Means how does
they differ from each other?

Thanks

--
Posted via http://www.ruby-forum.com/\.

PS: "nesting" reminds undefined

s/reminds/remains/ - non-native phonetic lapsus :).

Xavier Noria wrote in post #1122837:

3. If the enclosing class or module is a module, check Object
explicitly,
by hand. That is not the case in the example.

- *If the enclosing class or module is a class* then?

Let's suppose it was not found.

4. Call const_missing if implemented (this is a method lookup, could be
inherited).

I know `const_missing` is a hook method,which is called
automatically,when constant is not found. But in constant look up why
does it take into account?

At Last, Thank you very much for givng your continuous time for helping
me to climb up the concept ladder.. :slight_smile:

···

On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby <lists@ruby-forum.com>

--
Posted via http://www.ruby-forum.com/\.

Worth reading, I think http://rkh.im/code-reloading

I also wrote something related the topic based on discussions on the ruby
rogues list. It's still incomplete, but probably worth the reference

···

On Sun, Sep 29, 2013 at 11:27 AM, Xavier Noria <fxn@hashref.com> wrote:

I enjoyed the talk.. Although I need to watch 2 more times the previous

one. I have one question to you. Did you write any blog on the same
topic.

Not really. I'd like to write a little book about constants in Ruby, since
it such a fundamental topic, not very well understood in my experience, and
even less documented. Maybe someday.

"The Ruby Programming Language" has a section about constant lookup, but
it does not mention autoloaded constants (via Kernel#autoload, not related
to Rails autoloading, see below).

Xavier Noria wrote in post #1122837:

    module A::B
      include M

      class C::smiley: < E::F
        include N

         X
      end
    end

1. Check the nesting, from the most inner scope to the most outer scope.
That is, C::smiley: first, then A::B. It is important to highlight that Object
does NOT belong to the nesting. In each element of the nesting, check if
the constant belongs to the class or module itself, ignoring ancestors.
In
particular, in (1) the algorithm totally ignores N, E::F, and M. It
really
only looks up in the constant tables of C::smiley: and A::B.

Let's suppose it was not found.

2. Inspect the ancestors of the enclosing class or module. In the
example
N, E::F, Object, Kernel, BasicObject in that order (assumes >= 1.9 and
that
E::F inherits from Object).

Let's suppose it was not found.

3. If the enclosing class or module is a module, check Object
explicitly,
by hand. That is not the case in the example.

I have an example -

X = 12
module A
  module B
    module C
      p X
      $a = Module.nesting
      $b = ancestors
    end
  end
end
$a # => [A::b::C, A::B, A]
$b # => [A::b::C]
# >> 12

step-1 and step - 2 failed here to print the output of X,step-3 got
success..and print the value of X. Very interesting algorithm.. I
understood.

Could you give one example,where success should come from step-4.

···

--
Posted via http://www.ruby-forum.com/\.

Xavier Noria wrote in post #1122837:

4. Call const_missing if implemented (this is a method lookup, could be
inherited).

Let's suppose it was not found.

Hope this is what you told in step - 4 right?

module A
  module B
    module C
      def self.const_missing(name)
        p name,14
      end
      X
      $a = Module.nesting
      $b = ancestors
    end
  end
end
$a # => [A::b::C, A::B, A]
$b # => [A::b::C]

# >> :X
# >> 14

If not,please give one good example. :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

Xavier Noria wrote in post #1122972:

Module::nesting I understood..But I am bit confused with
Module::nesting,Module::constants and Module#constants --- What are the
use cases(nesting I know,helps to look up constants) ? Means how does
they differ from each other?

The constants API and nesting are totally different concepts.

Module.constants is documented here:

    Class: Module (Ruby 2.0.0)

and Module#constants here:

    Class: Module (Ruby 2.0.0)

Try this snippet:

    module M
      X = 1
    end

    p Module.constants
    p M.constants

On the other hand Module.nesting returns the "namespaces" at the point of
execution, from inner to outer. See

    p Module.nesting

    module M
      p Module.nesting
      module N
        p Module.nesting
        class C
          p Module.nesting
        end
      end
    end

Nesting is used to resolve relative constant names, as explained previously.

···

On Tue, Oct 1, 2013 at 9:21 PM, Love U Ruby <lists@ruby-forum.com> wrote:

> On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby <lists@ruby-forum.com> > > wrote:

Xavier Noria wrote in post #1122837:

> 3. If the enclosing class or module is a module, check Object
> explicitly,
> by hand. That is not the case in the example.

- *If the enclosing class or module is a class* then?

In that case the algorithm skips (3) and goes to (4).

Most classes have Object among their ancestors, so the constant will be
found in (2) for the majority of them. Indeed all classes had Object among
their ancestors before 1.9 but with BasicObject that is no longer true.
This introduces a gotcha, for example

    class C < BasicObject
      String # raises NameError
    end

raises NameError, because the String constant belongs to the constants
table of Object, which is not an ancestor of C, and (3) is skipped for
classes. So, NameError. No top-level constant works in that class body
using a relative name, you have to switch to an absolute constant path:

    class C < BasicObject
      ::String # works
    end

Note you must use the leading double colon syntax, this doesn't work:

    class C < BasicObject
      Object::String # raises NameError
    end

because in such constant path the first segment is resolved as a relative
name, only the second and subsequent segments are resolved with the other
algorithm.

That exercise makes apparent that Object is a regular Ruby constant, is not
a global special class or syntax for class names or anything like that,
just an ordinary constant that yields a class object that happens to be
created by the interpreter when it bootstraps.

You can technically remove_const String from Object. Nothing would work,
but you can, they are not special-cased.

> Let's suppose it was not found.

>
> 4. Call const_missing if implemented (this is a method lookup, could be
> inherited).
>

I know `const_missing` is a hook method,which is called
automatically,when constant is not found. But in constant look up why
does it take into account?

Well, for const_missing to do its work someone has to call it :). That
someone is the constant name resolution algorithm.

At Last, Thank you very much for givng your continuous time for helping

me to climb up the concept ladder.. :slight_smile:

It took me some research to figure all this out and I sympathize with your
curiosity, which is like mine was back in the day :). Very glad to share.

···

On Sun, Sep 29, 2013 at 10:02 PM, Love U Ruby <lists@ruby-forum.com> wrote:

> On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby <lists@ruby-forum.com>

Yeah, basically whatever const_missing returns is considered to be the
value of the constant:

    class C
      def self.const_missing(*)
        1
      end
    end

    C::X # => 1
    C::Y # => 1

Rails uses const_missing to intercept unknown constants and load files on
demand based on naming conventions. In the case of Rails, if loading
succeeds the constant gets actually defined because the file that defines
it is interpreted. Thus, in Rails const_missing is triggered only once per
constant.

Xavier Noria wrote in post #1123075:

The constants API and nesting are totally different concepts.
and Module#constants here:

    Class: Module (Ruby 2.0.0)

Okay! I tried the code below :

module A
  module B
    Z = 2
  end
  X=10
end
module A::B
  module C
    Y =10
  end
end
A.constants
# => [:B, :X]

It seems Module#constants - which Returns an array of the names of the
constants accessible in mod A. Not from the nested modules. Now my
questions is - Can we do something by which A.constants can output as
[:B, :X,:Z,:C,:Y] ?

···

On Tue, Oct 1, 2013 at 9:21 PM, Love U Ruby <lists@ruby-forum.com> > wrote:

A::b::C::Y # => 10

--
Posted via http://www.ruby-forum.com/\.