Recap: include and the ancestor chain

Free preview 3 min to read

One line you've already written, looked at closely

In Ruby modules: include/extend you wrote include SomeModule inside a class body to mix a module's methods into every instance of the class. This course doesn't reteach that. It answers a sharper question the earlier course only touched on: when Ruby looks for a method, in what order does it check the places the method could live?

module Startable
  def start
    "engine turns over"
  end
end

class Car
  include Startable
  def start
    "car starts smoothly"
  end
end

Car includes Startable and also defines its own start. A call to Car.new.start runs only one of these two method bodies. Which one runs, and why, comes down to one method every class responds to: .ancestors.

.ancestors: the search order

Car.ancestors
# [Car, Startable, Object, Kernel, BasicObject]

That array is the order Ruby walks when you call a method on a Car instance. Ruby checks Car, then Startable, then Object, then Kernel, then BasicObject. It stops at the first place that defines the method being called.

Car.new.start
# "car starts smoothly"

Car comes first in the array and defines start, so the search stops there. Startable#start exists and sits in the ancestor chain, but it never runs. Car's own method wins because Ruby checks Car first.

When the class doesn't define it

class Motorcycle
  include Startable
end

Motorcycle.new.start
# "engine turns over"

Motorcycle never defines start. The search starts at Motorcycle, moves through its ancestors, reaches Startable and stops there. It's the same algorithm with a different outcome, because this time nothing earlier in the chain got in the way.

The pattern so far

include inserts a module right after the class in .ancestors, and that's the whole rule. The class's own method sits before the module in the chain, so it wins when both define the same name. The module only gets a turn when the class doesn't define that method.

That fact, module after the class, is about to get a counterpart. The rest of this course is about one more keyword that puts a module in a different spot in the same array, and what follows from where it lands.

Where this course goes

There are seven lessons. This one recaps where include puts a module. Then come prepend and where it lands, .ancestors for both side by side, and a trace showing which method body runs first. After that: how super behaves inside a prepended module, both keywords on one class, and a final lesson on choosing between them. Each claim is checked by running code.

Key takeaways

  • .ancestors returns the ordered list Ruby walks to find a method.
  • include inserts a module right after the class in that list: [Car, Startable, Object, Kernel, BasicObject].
  • Because the class comes first, its own method wins over an included module's method with the same name.
  • When the class doesn't define the method, the search continues down the chain and reaches the module.
Lesson 1 of 7 · free

Keep going with lesson 2

prepend inserts a module before the class

Shows that prepend puts the module before the class, so its method runs first and controls the call.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...