Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

elixir: why two boolean operators for the same operation

Tags:

elixir

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?

like image 226
tldr Avatar asked Jan 05 '16 06:01

tldr


3 Answers

According to the Elixir Tutorials on Basic Operators:

or and and 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 and not when you are expecting booleans. If any of the arguments are non-boolean, use &&, || and !.

My Take

  1. To me it seems to be best practice within the language itself.
  2. Inline with the let it fail philosophy, being more strict with types could be a good idea in comparison situations.In iex(5) the result throws an ArgumentError. Throwing such an error may be a better idea than wrongly evaluating something.

&& 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
like image 64
ham-sandwich Avatar answered Oct 08 '22 11:10

ham-sandwich


Ok, straight from the source of truth for all things Elixir:

Two main reasons:

  1. Writing assertive code: if you are expecting a boolean, use a boolean
  2. 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.

like image 24
Onorio Catenacci Avatar answered Oct 08 '22 11:10

Onorio Catenacci


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
like image 5
coderVishal Avatar answered Oct 08 '22 12:10

coderVishal