This is a loose translation of my post from 2018.
Ruby is a very complex programming language. It’s incredibly beautiful and expressive. However, it also has lots of traits and implementation details that even some of the experienced Ruby programmers may not know. One of these is constant lookup.
I’m not gonna try to explain the lookup algorithm works. I just want to raise some awareness of the topic. Mostly, it’s just a rant.
Let’s make a little demonstration. Let’s start with a few constants:
We have a mixin module
M and a module
Namespace with a subclass
module defines a constant
A which we are going to try and access.
A quiz. What will the code below print out? I’ll put the answers a bit further so they don’t spoil the fun.
Let’s also define a few methods:
What do you think? Are they different?
Here’s the full code from our demo with answers in it:
So the output will be:
A from M A from Namespace A from Namespace A from M A from M
Simply speaking, constant lookup includes a few steps:
- Lexical scope search. I.e. the lookup context will depend on the place where
the line of code is. For example, in the first
putsthe execution context is the top-level so it uses the constant
Namespace::C::A. During the second
puts, it first changes the context to
Namespacemodule, then the
Cclass, and only then looks
Aup. You can find more about that if you read about nesting and
- If the first step wasn’t successful, the interpreter starts going through mixins and parent classes for every module from the first step.
- If even that didn’t help, the top-level gets checked. Technically, it’s
included in the step 2 because top-level is an
- At this stage the constant is considered missing and the
const_missingmethod is called (similarly to
Ruby Style Guide has a good rule of thumb: define and extend classes/modules using explicit nesting, i.e. never write `class A::B`. Following this simple rule is, practically, enough to avoid surprises and to be oblivious of constant lookup completely.
What else you can read on the subject:
- Chapter 7.9 of “The Ruby Programming Language” - book written by Matz.
- Autoloading and Reloading Constants in Rails guides
- Ruby Style Guide
- Play around with Module.nesting
User @DsideSPb left a useful comment about an additional feature of constant lookup. However, it was deleted in the last ruby release (2.5.0).
I don’t know all the details but in some cases if you specify wrong way to the constant, interpreter may replace it with one from top-level.