Page Content

Tutorials

What Is Mean by Method Resolution In Ruby With Code Example

Method Resolution in Ruby

The dynamic mechanism Ruby employs to decide which method definition should be called when an object gets a message is called Method Resolution (sometimes called Method Lookup or Method Name Resolution).

The idea behind object-oriented design in Ruby is that objects receive messages and respond to them; invoking a method is equivalent to sending a message. Any parameters and the method name are specified in the message. Ruby message forwarding is dynamic, therefore the choice of which method to execute is postponed until the program executes.

The last evaluated expression in the method’s body yields the value of the method invocation expression.

You can also read What Is Command Line Crash Course Navigation In Ruby

The Method Resolution Algorithm

Ruby looks for the method definition by following a predetermined set of rules when evaluating a method invocation expression, such o.m (where o is the object and m is the method name):

Eigenclass Check: Ruby begins by examining the object (o)’s eigenclass for singleton methods with the identifier m. Ruby looks through the superclass (and its ancestors) of an object in addition to the singleton methods in its eigenclass.

Class Check: Ruby looks through the class of o for an instance method called m if the method is not present in the eigenclass.

Module Check (Mixins): Ruby looks through any modules that the class of o includes for instance methods if the method is not present in the class. The most recently added module is searched first if a class has more than one module. This is done in the opposite order that the modules were added.

Inheritance Chain Climb: The search proceeds up the inheritance structure to the superclass if the method is still not located. For every ancestor class and its contained modules, steps two and three are repeated until the definition is located.

Handling Missing Methods: A method called method_missing is invoked in a second resolution step if, after examining the whole inheritance and module chain, no method named m is discovered. The Kernel module has a default implementation, therefore this method call is assured to succeed.

This procedure guarantees that the most specialized version of a method that is appropriate for the object is used and that subclasses can redefine or override methods that were passed down from their parents.

You can also read What Is The Command Line Crash Course Manipulation in Ruby

Code Examples Illustrating Method Resolution

Inheritance and Method Overriding

The method resolution mechanism makes ensuring that the right version of a method is called when it is overridden in a subclass, even if the method is called from inherited code.

In the example below, SpanishWorldGreeter inherits the greet method from WorldGreeter, but overrides greeting. When greet is called on an instance of SpanishWorldGreeter, the lookup resolves greeting to the subclass definition:

class WorldGreeter
  def greeting
    "Hello"
  end
  def greet
    puts greeting + " World"
  end
end

# Greet the world in Spanish
class SpanishWorldGreeter < WorldGreeter
  def greeting                   # Override the greeting
    "Hola"
  end
end

# We call the greet method inherited from WorldGreeter, 
# but greeting resolves dynamically to the subclass version.
SpanishWorldGreeter.new.greet 

Output

Hola World

The “Hola World” response shows that Ruby does this lookup at runtime.

In the event that a method is defined farther up the chain and cannot be overridden, the lookup keeps going until it locates the definition. Considering the classes Example and SubExample, for instance:

class Example
  # Define the method in the parent class
  def example_method
    :example
  end
  # ... other methods/definitions ...
end

# SubExample inherits from Example
class SubExample < Example
  # ... no definition for example_method, it inherits it
end

# 1. Instantiate the subclass (using the correct capitalization)
s = SubExample.new

# 2. Call the inherited method and explicitly print the result
# The method is found in the parent class 'Example'
puts s.example_method

Output

example

After checking SubExample and failing to find a defined method, Ruby proceeds up the chain to Example, where it locates and utilizes Example#example_method.

Using

Ruby calls method_missing if it is unable to locate a defined method after examining the complete ancestry chain. This enables dynamic object responses to undefined methods.

class Animal
  def method_missing(method, *args, &block)
    # This line returns the string, but does not print it.
    "Cannot call #{method} on Animal"
  end
  
  # It's good practice to include respond_to_missing? 
  def respond_to_missing?(method, include_private = false)
    true
  end
end

animal = Animal.new

# FIX: Use 'puts' to display the return value of method_missing 
puts animal.say_moo

Output

Cannot call say_moo on Animal

Method_missing can be used to intercept and manage messages that were not specifically defined:

Any arguments supplied to the original invocation are passed to the method_missing implementation, along with the name of the missing method (as a symbol). Dynamic behaviors like delegation, proxies, and the use of Domain-Specific Languages (DSLs) all depend on this technology.

You can also read Method Visibility In Ruby : Public, Private, And Protected

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index