The horrible cost of using explicit returns in Ruby….

At my lovely new job, we got a trainer to teach us about Ruby, Rails, and agile methodologies. She was pretty good overall, but one thing she mentioned a few times really got on my nerves: “use implicit returns in Ruby because there is a performance hit when explicitly returning”.

So first, what do we mean by implicit vs. explicit returning in Ruby? Here’s an example: say you have a method that needs to return a number based on a comparison, as is typically useful for sort and family. (Obviously this is a very contrived use case, and you wouldn’t likely implement a comparison function like this. It’s an example.)

Here are two ways we could implement this method:


    # Implicit return - Ruby returns the last value evaluated, so
    # with if/elsif/else, we can be sure we return the right value!
    def comparison(a, b)
      if (a.field < b.field)
        -1
      elsif (a.field > b.field)
        1
      else
        0
      end
    end

    # Explicit returns - we add "return" all over the code
    def comparison(a, b)
      if (a.field < b.field)
        return -1
      elsif (a.field > b.field)
        return 1
      else
        return 0
      end
    end

At first glance, it seems pretty obvious what’s different between the two, and it would seem that calling “return” explicitly is a waste of time….

But then again, if you’re not a complete programmer noob, you might notice something that sets the two apart: ease of refactoring.

In the implicit return scenario, your code can’t be cleaned up much. You could go with a targetless case statement, but that’s awkward to look at and makes the return less obvious. You could nest ternary operators, but again, that’s making the returns hard to find. Furthermore, if you decide to add some logic to the code for some reason, adding it at the bottom would destroy the function since Ruby will return the last evaluated statement — this means complex code can break without it being very obvious.

In the explicit return scenario, on the other hand, you can not only make it more concise, but also easier to read for some people by returning early and avoiding the use of else. And by explicitly returning, anybody looking at the function can quickly see that the function returns at three very clear points. And unlike what could happen in the first scenario, adding code at the end of this function will not break the return value.

So to illustrate a more concise, safe, and explicit example:


    # Using statement modifiers for very few lines of code
    def comparison(a, b)
      return -1 if a.field < b.field
      return 1 if a.field > b.field
      return 0
    end

    # Simpler but longer example - still avoids elsif and else
    # and is safe from adding code at the end
    def comparison(a, b)
      if a.field < b.field
        return -1
      end

      if a.field > b.field
        return 1
      end

      return 0
    end

Obviously I favor explicit returns, and nobody will convince me that doing it implicitly is better (isn’t Ruby supposed to be about readability?) So to hear there is a performance hit and that alone is a good reason to use implicit returns makes me really wonder about people.

A performance hit? In Ruby?!? Okay, let’s take a second here. Ruby as a language is SLOW, and you need to accept that to write good Ruby, because you have to be ready for it if you need a particularly CPU-intense algorithm or application. You need to know how to cut corners, how to implement C libraries, etc. So naturally on hearing somebody discussing the “fast” way to do something so trivial in Ruby, my skeptic senses tingled.

I ran a quick benchmark and found that over one million iterations, implicit and explicit returns showed a difference of about 3/10 of a second. Percentage-wise, implicit returns are the clear winner, clocking about 30% less time over multiple million-iteration runs — but the overall difference works out to a cost of about 300 nanoseconds per call. In an app where this difference will EVER matter, Ruby is absolutely the wrong choice of language.

14 Replies to “The horrible cost of using explicit returns in Ruby….”

  1. I really haven’t found “(isn’t Ruby supposed to be about readability?)” to be true at all. The reality is probably that the programming idioms made possible by the language allow for inherent obfuscation of intent and that is what I am seeing. Good tool, bad craftsmen.

    Great article, though. I’ve encountered many developers who repeat that statement almost as a mantra.

  2. In a forum an expert argued for the use of Implicit Return. Pointing out gain of speed writing the code, also acknowledged the imperceptible speed gains of its execution. My question was: If important to document code && execution speed gain is negligible then why save typing time in skipping 6 clicks of ‘return’ to type words explaining use of Implicit Return. How and who gained? Web development demands familiarity of PHP, JavaScript, HTML&CSS, Python,…blah and interactions. Documenting maintainable code is high, language speed low. Question to sober & seasoned developers: Shortcuts versus strict syntax. Really, how many developers/coders use implicit return and who uses shortcuts? 2 dialects? Quircky? Isn’t this the reason why many programmers avoided BASIC? One standard is nice. YUP I==’nuwbie’

  3. Your ruby code is terrible, and your instructor was misguided. Raw speed is almost never a determining factor for why we do anything in ruby. If it was, we probably wouldn’t be using ruby in the first place. One of the more elegant features of ruby that goes over newcomers’ heads is that everything is an expression. Adding early returns everywhere breaks that.

    Your ideas about “safety” are horribly stupid. If people are indiscriminately adding code to your methods, you have bigger problems. After all, what’s to stop this hypothetical chucklehead from adding more early returns to the beginning of your “safe” method. Learn to understand expressions properly, and neither you nor your fuckwit coworkers will imagine you have this problem.

    1. My good dear sir:

      Ruby code is terrible. All of it. Ruby is one of the worst atrocities to ever have come from the programming community (node.js being a very close second). That I have bigger problems is not in dispute here, but over-paranoia regarding code safety is the reason languages like Rust, Erlang, and even Go have gotten so much traction. And why languages like Ruby, which emphasize magic over understanding, are slowly starting to see their demise. Hidden magic disguised as elegance is just garbage carefully covered over by a tarp.

      So, my good fellow (or madam, as the case may be), I say with the utmost sincerety that you would be better served to go fuck yourself rather than tarnish the world with what is likely terrible code.

      1. Yeah frankly if Ruby ever does a python 3 style “Remove cruft and tighten up the language” iteration, implicit returns really need to go. At the very least Linter packages should throw big red flags up when people use them. Theres just too much oportunity to mess up whats actually been returned (And I’ve seen a LOT of this sort of bug working on other folks code).

        I’m a bit surprised about implicit returns being “faster”. That seems like something terrible has happened in the interpreters implementation, I just cant think of a single sensible reason why it would be so.

        1. I don’t see Ruby removing cruft anytime soon; it seems like “MOAR MAGIC” has been a driving force for Ruby (possibly thanks in part to Rails) for years. Which is unfortunate. I don’t use Ruby very often, and when I do it’s like re-learning the language.

          As for the speed difference, it’s really a great question. But bear in mind my benchmarking was over six years ago, and probably with Ruby 1.8 or 1.9. Today’s Ruby (at least what I just pulled from docker) suggests there is no longer any difference in speed. I suspect there was indeed something stupid going on in those older versions. Of course, I stand by my claim that we shouldn’t worry about negligible performance gains compared to readability. Especially in Ruby and other slow-ish languages.

        1. Python is far preferable to Ruby for me. Despite the fact that I don’t use either one on a daily basis, I can jump into Python a lot more quickly than Ruby. It’s more explicit and there’s far less magic. I still find runtime errors to be a major nuisance, but they don’t tend to be nearly as difficult to trace as in complex Ruby applications.

  4. I’m a big fan of explicit returns as well for anything even moderately complicated. There’s just NOT ONE good reason against be explicit.

    Nitpick: 3/10ths of a second is 300 milliseconds. Easily observable by a human. 300 nanoseconds is not.

    1. Yeah, re-reading my sentence above, it’s definitely not as clear as it could have been. What I was saying was that 300ms was the average cost when I ran multiple million iteration tests. Each test did the call 1,000,000 times, and the cost for all million was 300ms, which is why it works out to a 300ns cost per call.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.