LaunchKit
All quizzes
Ruby 0 views

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

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.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.