Elixir Boolean Operators

Elixir is confusing. Here’s one of the reasons:

iex> true and false

and

iex> true && false

do the same thing.

There is one difference between the two of them though: the former only works with booleans, and if you don’t give it booleans it starts crying (its crying sounds something like ** (BadBooleanError) expected a boolean on left-side of "and"). The latter, however, is a bit more permissive, allowing you to write conditions involving anything. They’ll evaluate everything to true, except for false and nil:

iex> 1 || true
1
iex> nil && 13
nil
iex> %Object{property: value} && %AnotherObject{property: value}
%AnotherObject{property: value}
iex> 13 && 15
15
iex> 13 || 15
13

Neither set checks the second condition if the first one is enough to determine the result. For example:

iex> false and raise("This error will never be raised")
false
iex> true || raise("This error will never be raised")
true

You can use either for writing inline if-else conditions:

iex> date = ~D[2016-10-01]
iex> Date.day_of_week(date) == 6 && IO.puts("Saturday")
"Saturday"
iex> Date.day_of_week(date) == 3 and IO.puts("Wednesday") or IO.puts("Saturday")
"Saturday"

ALSO You can use either to replace the if-else blocks when assigning values to variables:

iex> date = ~D[2016-10-01]
iex> new_date = Date.day_of_week(date) == 6 && Date.add(date, 3)
~D[2016-10-04]
iex> other_date = Date.day_of_week(date) == 3 and Date.add(date, 3) or Date.add(date, 10)
~D[2016-10-11]

In order to negate each of them, you have not and !, respectively.

iex> not true
false
iex> not 1
** (ArgumentError) argument error
    :erlang.not(1)
iex> !true
false
iex> !1
false
iex> !nil
true

The logical operators are also very useful when wanting to work with objects that might be nil under certain circumstances (e.g. fetching a user from the DB by id might return nil if the user doesn’t exist). Therefore, before doing a check on an object’s property, we can simply:

user = fetch_from_db(id)

if user && user.role == "admin" do
  # whatever we want to do with the user if it's an admin
end

Which can also be written as:

user = fetch_from_db(id)

if not is_nil(user) and user.role == "admin" do
  # whatever we want to do with the user if it's an admin
end

Conclusion: use && and || only when you’re not working with booleans, but otherwise stick to and and or. there’s not much of a difference between the two sets, it depends on your preference; you can write most conditions by using either set, though &&-|| is a bit more permissive.

Alexandra Docolin

Developer. React-Native worshipper. Please don't ask me about tests 😊

Tags
Elixir