Ruby offers conventional control structures that are found in most common programming languages like
while, however, Ruby also provides less common options like
unless. These control structures may seem weird at first (“who talks like that?”), but they have their advantages.
Let’s start with a basic
if statement. Here we have a
Movie class with several attributes and functionality to only update a movie’s title if the
in_progress attribute is
true; easy enough. If
in_progress is true, then the
title attribute can be assigned a new value.
class Movie attr_accessor :in_progress attr_reader :title, :length, :budget def title=(new_title) if @in_progress @title = new_title end end end
Now let’s imagine if the attribute was
finalized instead of
in_progress. It may be tempting to put a
! in front of it and call it a day.
class Movie attr_accessor :finalized attr_reader :title, :length, :budget def title=(new_title) if not @finalized @title = new_title end end end
This if statement is valid but is a little more verbose than it has to be. An alternative (and slightly more concise) way would be to use
class Movie attr_accessor :finalized attr_reader :title, :length, :budget def title=(new_title) unless @finalized @title = new_title end end end
unless, the body of the statement (
@title = new_title) is only executed if the condition (
unless comes with a couple of benefits:
- It’s slightly shorter that using
- It may become a little easier to read and understand once you get used to it
The second point is important. Reading an
unless statement may seem weird at first (when I first encountered it in a production app I had to read it as “if not” until I got used to it). But after a while it becomes less awkward and just another way to do a negative, or backwards, if statement.
There’s no “right” way to do it; it’s just a preference. The difference between an
if not and
unless is like saying:
- “It is
not truethat an apple is an orange”
- “An apple is not an orange”
unless is the negative version of
until is the negative version of
while loop will keep looping while the condition (
! download.is_finished?) is
true. In this example, the condition reads “while not download is finished (execute the code block)”.
while !download.is_finished? spinner.keep_spinning end
until loop will keep looping until the condition (
true. In this example, the condition reads “until download is finished (execute the code block)”.
until download.is_finished? spinner.keep_spinning end
Again, it’s a matter of preference; but using
until became clearer once I understood the difference and became used to it.
We can also make these examples a little more concise and readable. Notice how the code block of the statements are only one line? Because it’s only one one line and is pretty short, we can condense the statements to just a single line.
spinner.keep_spinning while !download.is_finished?
spinner.keep_spinning until download.is_finished?
Just as before, it’s a matter of preference, but to me using
until is clearer and reads a little better.
That’s part of the reason I really like writing code in Ruby, there are multiple ways to do the same thing. The language provides tools you need to express yourself and does its best to stay out of your way. Does
not if make more sense to you or does writing
unless statements feel more natural? Either way is fine because Ruby provides both options! Same thing with
This article was originally published on anthonygharvey.com on March 5th, 2019.