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

On Sun, Sep 29, 2013 at 12:45 AM, Love U Ruby [email protected]
wrote:

Hi,

end
end

NameError: uninitialized constant C::D::B

A::B is a constant of A, but A is not in the nesting in line L, nor it
is
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.

Xavier N. wrote in post #1122778:

On Sun, Sep 29, 2013 at 12:45 AM, Love U Ruby [email protected]
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?

On Sun, Sep 29, 2013 at 1:15 AM, Love U Ruby [email protected]
wrote:

Xavier N. wrote in post #1122778:

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.

On Sun, Sep 29, 2013 at 8:43 AM, Love U Ruby [email protected]
wrote:

Code A:

Code B:

>> [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.

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?

Xavier N. wrote in post #1122790:

On Sun, Sep 29, 2013 at 1:15 AM, Love U Ruby [email protected]
wrote:

Xavier N. 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,

PS: “nesting” reminds undefined

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

On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby [email protected]
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 P.ming 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::D < 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.

  1. 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.

  1. 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.

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

Let’s suppose it was not found.

  1. 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 10:02 PM, Love U Ruby [email protected]
wrote:

Xavier N. wrote in post #1122837:

On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby [email protected]

  1. 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.

  1. 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.

Xavier N. wrote in post #1122837:

module A::B
  include M

  class C::D < 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.

  1. 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.

  1. 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.

Xavier N. wrote in post #1122837:

On Sun, Sep 29, 2013 at 4:07 PM, Love U Ruby [email protected]

  1. 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.

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

Xavier N. wrote in post #1122837:

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

Xavier N. wrote in post #1122939:

it is interpreted. Thus, in Rails const_missing is triggered only once
per
constant.

In Ruby why is the exception?

class C
@x = 0
def self.const_missing(*)
1 # !> unused literal ignored
@x=+1
end
def self.val
p @x
end
end

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

>> 1

I expected C.val should print 2.

The code has a typo, should be

@x += 1

rather than

@x = +1

Xavier

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.

On Sun, Sep 29, 2013 at 11:27 AM, Xavier N. [email protected] wrote:

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

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
http://www.benjaminfleischer.com/2013/07/18/ruby-requires-confusion/

On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby [email protected]
wrote:

Xavier N. 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

Xavier N. wrote in post #1122972:

On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby [email protected]
wrote:

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

Thanks

On Tue, Oct 1, 2013 at 9:21 PM, Love U Ruby [email protected]
wrote:

Xavier N. wrote in post #1122972:

On Tue, Oct 1, 2013 at 6:30 AM, Love U Ruby [email protected]
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?

The constants API and nesting are totally different concepts.

Module.constants is documented here:

http://ruby-doc.org/core-2.0.0/Module.html#method-c-constants

and Module#constants here:

http://ruby-doc.org/core-2.0.0/Module.html#method-i-constants

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs