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 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 &&
and ||
only when you’re not working with booleans, but otherwise stick to and
and or
.&&
-||
is a bit more permissive.
Developer. React-Native worshipper. Please don't ask me about tests 😊