DEV Community

Lucian Ghinda
Lucian Ghinda

Posted on • Originally published at allaboutcoding.ghinda.com

History of the endless method syntax

Discover how Ruby's endless method syntax has developed from its early suggestions in 2011 up to its release in 2020 part of Ruby 3.

When I learn about a new language feature, I like to read and discuss the proposal. How and why it was accepted. What was the requester trying to accomplish, and what problem did they try to solve?

Here, I will review how the endless method was introduced in the Ruby language.

What is the definition of the endless method?

In a few words, it is an alternative syntax for defining a method that consists of a single expression.

Here is the definition from Ruby documentation:

Definition of endless method in Ruby

Here are two simple examples:

def exists? = User.where(organisation: organisation).exists?
Enter fullscreen mode Exit fullscreen mode

or with parameters:

def format_date(date) = date.strftime(DEFAULT_DATE_FORMAT)
Enter fullscreen mode Exit fullscreen mode

History of trying to remove one or more ends

2011 - the first proposal is made mainly as a joke, but it tries to solve a real problem with idiomatic code

In 2011, Yasushi Ando proposed (as a joke) an en(n+)d to solve the following issue: having too many ends:

# Source: https://bugs.ruby-lang.org/issues/5054

# Replace this code:

module MyModule
  class MyClass
    def my_method
      10.times do
        if rand < 0.5
          p :small
        end
      end
    end
  end
end

# With:
module MyModule
  class MyClass
    def my_method
      10.times do
        if rand < 0.5
          p :small
        ennnnnd
Enter fullscreen mode Exit fullscreen mode

While the proposal was a joke, the idea is that sometimes the number of ends we have to write is high (sometimes it takes more chars than the actual business logic).

Another proposal (this time a serious one) was made by Lazaridis Ilias later the same year, 2011. This time the proposal was to allow } instead of end:

# Source: https://bugs.ruby-lang.org/issues/5065

module MyModule
  class MyClass
    def my_method
      10.times {   # "10.times do" would work, too
        if rand < 0.5
          p :small
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This one was rejected. Among other proposed ideas was to have an endall as a keyword that will add all necessary ends if I might say so:

# Source: https://bugs.ruby-lang.org/issues/5065

module MyModule
  class MyClass
    def my_method
      10.times do
        if rand < 0.5
          p :small
        endall
Enter fullscreen mode Exit fullscreen mode

2016 - another proposal was made, this time a serious one

Then, in 2016, Nobuyoshi Nakada proposed another idea, building upon the previous one: to introduce the end! keyword like a super end concept that will end all blocks not ended until its level:

# Source: https://bugs.ruby-lang.org/issues/12241

module MyModule
  class MyClass
    def my_method
      10.times do
        if rand < 0.5
          p :small
!end
Enter fullscreen mode Exit fullscreen mode

There were few replies to it, so there was no final decision.

2020 - a new proposal with more arguments and a simple approach is suggested

The feature request for the current format was submitted in 2020 by Yusuke Endoh on the Ruby issue tracker:

Endless method definition - proposal from Yusuke in Ruby tracker

The initial proposal wanted to use : instead of = when defining the method body, but Matz proposed using =. Still, the go-ahead for running an experiment like this was given at the end of 2020.

Later in that thread, Yusuke presented some arguments:

Surprisingly, according to the following rough estimate of ruby/ruby code base, this kind of simple method definitions account for 24% of the entire method definitions.

Victor Shepelev added some excellent arguments in favor of this proposal:

The most precious Ruby's quality for me is "expressiveness at the level of the single 'phrase' (expression)", and it is not "code golf"-expressiveness, but rather structuring language's consistency around the idea of building phrases with all related senses packed, while staying lucid about the intention

I believe that the difference of "how you write it when there is one statement" vs "...more than one statement" is intentional, and fruitful: "just add one more line to 10-line method" typically small addition, but "just add one more line to 1-line method" frequently makes one think: may be that's not what you really need to do, maybe data flow becomes unclear

2021 - a new proposal is made for a super-end keyword

While the status of the Yusuke proposal kept having multiple arguments, and Matz already proposed a syntax there that he would like but said might be conflicting, a new proposal was submitted trying to solve the same issue but focusing on nested ends.

This proposal added by Jabari Zakiya is about the same idea of how to reduce the number of end keywords, and in this case, the proposal was to use ends:

# Source: https://bugs.ruby-lang.org/issues/17786

def render(scene, image, screenWidth, screenHeight)
  screenHeight.times do |y|
    screenWidth.times do |x|
      color = self.traceRay(....)
      r, g, b = Color.toDrawingColor(color)
      image.set(x, y, StumpyCore::RGBA.from_rgb(r, g, b))
    end
  end
end

# To be replaced by

def render(scene, image, screenWidth, screenHeight)
  screenHeight.times do |y|
    screenWidth.times do |x|
      color = self.traceRay(....)
      r, g, b = Color.toDrawingColor(color)
      image.set(x, y, StumpyCore::RGBA.from_rgb(r, g, b))
ends
Enter fullscreen mode Exit fullscreen mode

This, too, not approved yet. Notice this is a bit of a tangent to the endless method, but it is worth considering that the idea that the number of end keywords written should be limited is present.

Ruby 3.0 - release on 25 December 2020 included endless method definition

Ruby version 3.0 included the endless method definition or shorthand method syntax with the following format:

def <name>(<params>) = <body>
# or
def <name>(<params>) = <an expression
    that can be on
    multiple lines>
# or
def <name> = <body>
# or
def <name> = <an expression
    that can be on
    multiple lines>
Enter fullscreen mode Exit fullscreen mode

Of course, having arguments is optional, but if you decide to specify them, then parentheses are mandatory.

More about the endless method

One of the best resources to read about this in a format that does an excellent assessment of this feature is the article written by Victor Shepelev called “Useless Ruby sugar”: Endless (one-line) methods

Curious to learn more about this?

If you want to learn more about this feature, its gotchas, when and how to use it, and real code examples, I am creating a course called “Modern Ruby Syntax”, where I explore the endless method along with other Ruby features.


Enjoyed this article?

👐 Subscribe to my Ruby and Ruby on rails courses over email at learn.shortruby.com- effortless learning about Ruby anytime, anywhere

👉 Join my Short Ruby News newsletter for weekly Ruby updates from the community and visit rubyandrails.info, a directory with learning content about Ruby.

🤝 Let's connect on Ruby.social or Linkedin or Twitter where I post mainly about Ruby and Rails.

🎥 Follow me on my YouTube channel for short videos about Ruby

Top comments (0)