alias vs alias_method across inheritance
Question
What is the return value of the following Ruby code?
class Device
def description
'I\'m a device'
end
def self.alias_description
alias describe description
end
end
class Microwave < Device
def description
'I\'m a microwave'
end
alias_description
end
m = Microwave.new
p m.description # => "I'm a microwave"
p m.describe # => ???
The correct answer is
-
"I'm a device"Correct -
"I'm a microwave"
Explanation
TL;DR
The alias keyword is resolved in the lexical scope where it is written. It sits inside a method defined in Device, so it aliases Device#description, even though the call that triggers it comes from Microwave's class body. m.describe returns "I'm a device", while the overriding m.description returns "I'm a microwave".
The alias keyword
class Device
def description
"I'm a device"
end
def self.alias_description
alias describe description
end
end
class Microwave < Device
def description
"I'm a microwave"
end
alias_description
end
m = Microwave.new
m.description # => "I'm a microwave"
m.describe # => "I'm a device"
Microwave.instance_method(:describe).owner # => Device
alias is a keyword, not a method call. It is resolved against the class that lexically encloses the def it appears in, here Device. So when Microwave calls alias_description, the alias is installed on Device and copies Device#description. The owner check confirms it: describe lives on Device, and Microwave's override of description is never consulted.
An alias also captures the method definition current at the moment it runs: redefining description afterwards does not change what describe returns.
Module#alias_method
alias_method is a regular method call, so it operates on whatever self is at runtime. When alias_description is invoked from Microwave's class body, self is Microwave: the alias is defined on Microwave and method lookup finds the most specific description, the one defined in Microwave:
class Device
def description
"I'm a device"
end
def self.alias_description
alias_method :describe, :description
end
end
class Microwave < Device
def description
"I'm a microwave"
end
alias_description
end
m = Microwave.new
m.description # => "I'm a microwave"
m.describe # => "I'm a microwave"
Microwave.instance_method(:describe).owner # => Microwave
The rule of thumb: alias follows the lexical scope, alias_method follows self. When writing code meant to be called from subclasses, alias_method usually does what you expect.
Share this quiz
Comments
No comments yet. Be the first.