Ruby guard clause FTW

A common Ruby programming idiom is writing guard clauses for immediate returns in lieu of nested if-elsif-elsif-elsif-end or case statements.

The Ruby 'guard clause' idiom

The guard clause idiom construction looks like this:

def even? number
  return true if number % 2 == 0

  false
end

Before going any further, I know Ruby has the even? method for doing exactly this. And I could easily generate a guard clause example using specialized domain knowledge. However, the example provides code everyone can easily follow, and the discussion is supposed to be focused on guard clauses, not implementations of Ruby library methods. Just wanted to clear that up.

The first line of the method is often called a “guard clause” because of the syntactic pattern of returning from the method early, given some condition.

But technically, isn’t a “real” guard clause code for trapping invalid parameters or states on method entry?

In our code above, all the values of the argument number are assumed valid, even a nil argument. There is no “guarding” going on.

What is going on, instead, is control of flow. Plain old programming in fact.

The real beef seems to be related to a zombie meme left over from structured programming, as promoted by Dijkstra: never have more than one return from a function, and that return must be the last line of the function.

Our code above seriously violates Dijkstra’s dictum.

Isn’t that a bad thing?

In my opinion, no, it’s not, at least not for the code as written above. It’s a small method, just a few lines. Back when structured programming was adopted, functions commonly had dozens (or even hundreds) of lines. Then it would make a lot of sense to limit each function to a single return statement, and require it to be at the bottom of the function.

But let’s look at the code above again. The return statements are almost equivalent to setting a return value on a conditional and jumping directly to the end of the method to return that value. Like with a goto statement.

And there isn’t anything wrong with that. Used correctly, goto statements, are an appropriate and even elegant way to control program flow. The Ruby C source code has gotos, and tastefully employed gotos are an accepted convention in Unix socket programming. There’s nothing intrinsically wrong with a goto statement.

The upshot is that a leading return may syntactically resemble a guard close, without being a guard clause.

And like any other technique, using it correctly is often as much a matter of taste as anything else.

Errors and exceptions

Suppose we require a guard clause to actually “guard,” what does that look like in Ruby? Given that argument checking should be performed in this method, here’s one way to do it:

require 'rspec'

class Guard
  def self.even? number
    return true if number%2 == 0

    false
  rescue NoMethodError => e
    raise e, 'bad argument type'
  end
end

describe Guard do
  it 'instantiates correctly' do
    expect(Guard.new).to_not be_nil
  end

  it 'returns true for an even number' do
    expect(Guard.even?(2)).to eq true
  end

  it 'returns false for an odd number' do
    expect(Guard.even?(1)).to eq false
  end

  it 'blows up for nil argument' do
    expect { Guard.even?(nil) }.to raise_error(NoMethodError, /bad arg/)
  end
end

Whether or not argument checking should be performed in the Guard.even? method is not relevant to this article; it’s a different discussion. We’re assuming, a priori, that we do need to check the argument.

Note also def-rescue-end (DRE) instead of begin-rescue-end (BRE). The begin is implied and removes a level of nesting to increase readability.

The design of the Ruby programming language allows ignoring a type check unless the underlying Ruby interpreter complains. This, in turn, allows us to proceed with computation of the common cases up front, and never worry about the error code unless there is an error. In C or C++ (or Java), this would not be possible, the argument checking would have to be performed on entry to the method. In Ruby that would look like this:

def even? number
  raise NoMethodError('bad arg') unless number.is_a? Integer
  return true if number % 2 == 0

  false
end

But now we’re checking the type every time the even? method is invoked. Wasteful and unnecessary. Note that this implementation also passes the specs given above.

Here’s a bit more discussion in some follow-on links.

More discussion on guard clauses (and the if statements they replace)

Any further investigation or discussion should start by reading Martin Fowler’s “Replace nested conditional with guard clause.” This is a very short article and code heavy. An experienced programmer can read it at a glance. Fowler’s definition of a guard clause is includes all methods with multiple returns on leading conditions. This is more expansive than the definition proposed here, which would restrict guard clauses to code which checks argument validity (type, range, etc.). That said, I use Fowler’s definition when discussing code with programmers.

Here’s the blog post I started to write: “Prefer guard clauses over nested conditionals.” I found this after extending the initial draft of this article to include some test code.

This article provides an example of using a guard clause to guard in the sense discussed above: Single exit point. Rereading, I’ve probably drawn a fair bit of material from the “Single exit point” article, hence, it can also be regarded as a reference for this blog post.

Part of the case for guard clauses comes from programmers exasperated with Alpine if statements. You know, those very long functions with deeply nested conditionals. I find such code difficult to read, but I have worked on a fair bit of legacy code with constructions as vastly ghastly as what’s shown in this article. Possibly not quite as “alpine,” but certainly as convoluted.

The readability of guard clauses depends on the reader. In this article, the author attempts to make a case for guard clauses with a coworker. The coworker finds guard clauses increase the difficulty of understanding the control of flow through a program. The author (and myself) find completely the opposite.

Here is a list of controversial rules for code in an open source Java project. About half way down, notice the rule for having a single return located at the last line of the method. Obviously, this rule precludes guard clause techniques in favor of exception handling. Also notice the wordiness of Java compared to Ruby. Whether this wordiness is a good or a bad thing is a certainly matter of taste. Personally, I prefer the conciseness of Ruby (and Python).

What drives the guard clause idiom?

Flattening the arrow is an excellent starting point for understanding conditions promoting a refactor from nested conditionals to guard clauses. You may find the examples slightly dated, but of major interest is Atwood’s Item #4: Always use an opportunity to return as soon as possible from a function. This is almost polar opposite of Dijkstra’s dictum. The notion of “clean code” changes over time, it’s a cultural artifact, machine don’t care.

Last but far from least, the discussion on Guard clause at (the) wiki is worth investigating in detail, as is the article on “The Arrow Anti Pattern.” Wiki at c2 is, of course, the original wiki. If you don’t know, now you know.

As you can see, guard clauses can be hot button topic with programmers adhering to Dijkstra’s Dictum of single exit points. Your opinion, or more likely, your team’s or team leader’s or bosses opinion will decide the day to day use of this idiom, but at least your opinion should be a bit better informed as a result of reading all the way down to here.