pragmatist
Patrick Joyce

March 24, 2012

The Elements of Ruby Style: Predicate Methods

A method that returns true or false is called a "predicate method".

In Ruby, there is a naming convention where predicate methods end with a question mark. For instance, if you have an Invoice class and are writing an instance method that returns whether the invoice has been paid or not, you would name the method paid?

This idiom helps improve readability by making Ruby code read more like English:

puts "This invoice has been paid" if invoice.paid?

Predicate methods should always return true or false. Because of the way that Ruby evaluates truthiness (false and nil are false; everything else evaluates to true) some people will advocate simply returning a "truthy" value. An implementation of Invoice#paid? that was truthy could look like this:

class TruthyInvoice
  attr_accessor :paid_at

  def paid?
    @paid_at
  end
end

invoice = TruthyInvoice.new
invoice.paid? # nil

invoice.paid_at = Time.now
invoice.paid? # 2012-03-24 20:45:59 -0400 

The above implementation of paid? will work fine in conditionals.

However, the intent of the paid? method is to tell you if the invoice has been paid, yet it is returning an instance of Time. This is confusing. The method would better represent the author's intent if it always returned a boolean. The most common way to ensure that a method returns true or false is to use the not operator (!) twice. This is read "not not" and would be used as follows:

class Invoice
  attr_accessor :paid_at

  def paid?
    !!@paid_at
  end
end

invoice = Invoice.new
invoice.paid? # false 

invoice.paid_at = Time.now
invoice.paid? # true

Using "not not" only requires two more keystrokes and it more closely matches the intent of the method. One of the maxims of good programming is to "be liberal in what you accept and strict in what you emit". Returning a boolean from predicate methods is being strict in what you emit.

More Articles on Software & Product Development

Agile With a Lowercase “a”
”Agile“ is an adjective. It is not a noun. It isn’t something you do, it is something you are.
How Do You End Up With A Great Product A Year From Now?
Nail the next two weeks. 26 times in a row.
Build it Twice
Resist the urge to abstract until you've learned what is general to a class of problems and what is specific to each problem.