When I first started programming in Ruby, using the and
and the or
operator always confused me.
Thus I avoided them because I didn’t want to worry about accidentally writing incorrect code. I think a lot of programmers do the same, and it’s a shame because incorporating both and
and the or
operators can lead to more concise and elegant Ruby code.
First, let’s get the biggest misconception out of the way. The and
and the or
operator are not the same thing as &&
and the ||
operator that most programmers are familiar with. The &&
and the ||
operators work to validate some kind of condition while the and
and the or
operators work more to handle control flow, kind of like your every day if
statements.
and
Let’s talk about and
first. The easiest way to think about the and
operator is a way to chain methods until a method fails. The English way to think about it is something like, “do this and then do that and then do that, until one of those actions fail”. Let’s say you’re giving a mailman directions on how to deliver mail. You give him a list of addresses to deliver mail to and you tell him to continue delivering the mails until you come across a mail where you can’t locate the address of.
I’m going to try to explain it with some code so that it’s easier to understand. One common thing that we all do when writing code is to assign a value to a variable and then calling a method on that variable. For example,
1 2 |
resident = Resident.find_by(id: params[:id]) resident.launch! |
This is something you would typically do in a Rails controller. You query for an ActiveRecord model, assign it to a variable, and then take an action on that variable instance. In the above example, you can utilize the and
operator and write the above like this instead.
1 |
resident = Resident.find_by(id: params[:id]) and resident.launch! |
The above does in one line what the first example did in two lines with one additional advantage. In the first example without the and
operator, the resident.launch!
will cause an exception if the resident = Resident.find_by(id: params[:id])
fails and returns nil
. However, in the example with the and
operator, resident.launch!
will only be executed if the resident = Resident.find_by(id: params[:id])
was executed successfully and an actual resident was assigned to the resident
variable. Thus, in this specific example, the version with the and
operator is more resilient.
How would we write the above example with a standard if
statement? It would be something like this.
1 2 3 |
if resident = Resident.find_by(id: params[:id]) resident.launch! end |
I think the above code snippet is pretty clear in its intentions too, but I personally prefer the version with the and
operator.
or
Let’s now talk about the or
operator. The or
operator, like the and
operator is meant to chain operations together with one slight difference. As we discussed above, the and
operator chains operations together until one operation fails. The or
operator on the other hand, chains operations together until an operation works. For example, let’s say we want to raise an exception if resident.launch!
fails for whatever reason. Not using the or
operator, we could do it like this.
1 2 3 |
resident = Resident.find_by(id: params[:id]) resident.launch! raise 'Resident launch failed' unless resident.launched? |
In the above example, we’re launching a resident, and then raising an error if the resident failed to launch. How would we write this utilizing the or
operator?
1 2 |
resident = Resident.find_by(id: params[:id]) resident.launch! or raise 'Resident launch failed' |
In line 2, we are attempting to launch the resident and if the resident launch failed, we are raising an error. The easiest way to comprehend this is literally read it like English: “Hey resident, launch yourself or otherwise raise an error”.
Conclusion
Ruby comes with a lot of tools included to make writing elegant code easier. I believe that the and
and the or
operators are one of such tools that make such endeavors easier to achieve. I hope that this post helps demystify what these two operators can do in helping you write better Ruby code.