Endless methods meet if false
Question
What is the return value of the following Ruby code?
class Greeting
def self.hello = "hello" if false
end
Greeting.hello # => ???
The correct answer is
-
nil -
"hello" -
It raises
SyntaxError -
It raises
NoMethodErrorCorrect
Explanation
TL;DR
The modifier if applies to the whole endless method definition, not to the "hello" body. The line parses as (def self.hello = "hello") if false, the condition is false, so the def never executes and Greeting.hello is never defined. Calling it raises NoMethodError.
Step by step
class Greeting
def self.hello = "hello" if false
end
Greeting.respond_to?(:hello) # => false
begin
Greeting.hello
rescue NoMethodError => e
e.class # => NoMethodError
end
Under the hood
Ruby 3.0 introduced the endless method definition: def name = expression defines a one-expression method without end. A statement modifier such as if false binds to the outermost expression of the line, so it guards the definition itself, exactly as it does with a classic def:
class Greeting
def self.hello; "hello"; end if false
end
Greeting.respond_to?(:hello) # => false
This works because def is not a declaration in Ruby. It is an expression, executed when reached, that defines the method and returns its name as a Symbol:
class Greeting
RESULT = (def self.hello = "hello")
end
Greeting::RESULT # => :hello
Skipping a def at runtime simply means the method never comes into existence.
Edge cases
To attach the condition to the body instead, parenthesize it. The method is then always defined, and its body evaluates to nil when the condition is false:
class Greeting
def self.hello = ("hello" if false)
end
Greeting.respond_to?(:hello) # => true
Greeting.hello # => nil
One more parser rule to know: setter methods cannot be endless. def x=(value) = value is rejected with a SyntaxError: "a setter method cannot be defined in an endless method definition".
Version notes
Endless method definitions were added in Ruby 3.0. Since Ruby 3.1 the body can also be a method call without parentheses (def greet = puts "hello").
Share this quiz
Comments
No comments yet. Be the first.