Elixir seems to have 2 boolean operators for each operation:
|| , or
&& , and
etc. The only difference is that for or, and
etc, the first argument itself has to be a boolean. What is the point of these second set of operators, when || , &&
etc seem to be able to handle everything?
According to the Elixir Tutorials on Basic Operators:
or
andand
are short-circuit operators. They only execute the right side if the left side is not enough to determine the result
To answer your question, what is the point of the second set of operators?; I think the tutorial puts it quite nicely.
As a rule of thumb, use
and
,or
andnot
when you are expecting booleans. If any of the arguments are non-boolean, use&&
,||
and!
.
My Take
&&
and and
Example
iex(1)> nil && 13
nil
iex(2)> true && 17
17
iex(3)> true and true
true
iex(4)> false and true
false
iex(5)> 73 and false
** (ArgumentError) argument error: 73
Ok, straight from the source of truth for all things Elixir:
Two main reasons:
- Writing assertive code: if you are expecting a boolean, use a boolean
- Guards are strictly booleans, so you have to use "and" and "or" in there
That's straight from Jose Valim.
Also Peter Hamilton (credit where credit's due) pointed out this enlightening message from Robert Virding, one of the creators of Erlang:
A little bit of history and some philosophy about boolean operators and guards.
Long-ago we explicitly decided to have boolean operators 'and', 'or', 'xor' and 'not' and not have truthy values. This was not because we weren't familiar with truthy logic, which we were being long-time C and lisp programmers, we just felt it was more logical (haha). These were originally all strict and only accepted boolean arguments. Later there came a desire for short-circuiting 'and' and 'or'. Instead of redefining 'and' and 'or' we added the new operators 'andalso' and 'orelse'. Originally these were andalso(bool,bool) and orelse(bool,bool) and would thus test the value of the second argument. This is later changed so that the second argument was not checked, for amongst other reasons that this is how it is in other languages and because of the possibility for tail-call optimisation. I have personally never had use of that.
I am personally not a fan of truthy operators and think 'nil' smells a bit like null in other languages.
About guards. Originally they were guard tests and considered an extension of the pattern matching with things that couldn't nicely be written as a pattern. A test either succeeded or failed. IMAO this made guards more consistent wrt content and handling failure/exceptions, which was just a failed test. When the allowed guards became complex they wandered to becoming guard expressions which return boolean values and then the guard as a whole became a boolean expression. This, I think, made it more difficult to explain why guards look and behave like they do.
I am marking this answer as community wiki because it's not really my answer per se.
Seems to me that wanting to have a boolean value as first argument can be helpful when you dont want to interpret any other value(or datatype) as true, as elixir will take anything for true except for nil and false. User may want to make sure that the argument is a boolean (either true or false) and not accidently except any other type of value.
Boolean operators like or, and, not expect true or false as their first argument
Relaxed boolean operators like ||, &&, ! can take arguments of any type. Any value other than nil or false is interpreted as true(truthy).
For example
x || y # gives x if x is truthy else y
x && y # gives y if x is truthy else x
!x # false if x is truthy , otherwise true
If you try
iex(5)> not 3
** (ArgumentError) argument error
:erlang.not(3)
iex(6)> ! 3
false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With