sat
sat

Reputation: 5709

Elixir - Argument error

Can someone please help explain why we get the argument error? Are we not supposed to check for truthyness this way? On Elixir 1.3

iex(1)> true and true
true
iex(2)> "true"
"true"
iex(3)> true
true
iex(4)> true and "true"
"true"
iex(5)> "true" and true
** (ArgumentError) argument error: "true"

Upvotes: 4

Views: 5503

Answers (3)

legoscia
legoscia

Reputation: 41527

Elixir has two sets of boolean operators:

  • or, and and not in principle require their arguments to be actual booleans, i.e. the atoms true and false
  • ||, && and ! accept arguments of any types, and check "truthiness".

Though in fact, or and and only check the type of the first argument. For any value of x, the expressions false or x and true and x will simply return x. This might seem confusing, but it allows using or and and as the last expression in a recursive function without impeding tail recursion. For example, consider this function, which checks whether all elements in a list are equal to 42:

def x([]) do
  true
end
def x([h|t]) do
  h == 42 and x(t)
end

Because and permits tail recursion, this function will run in constant stack space. If and would check the type of its second argument, the function would have to make a normal call one stack frame "deeper", and upon return perform the check and return the value.

Upvotes: 5

michalmuskala
michalmuskala

Reputation: 11278

The "wordy" boolean operators - and, or and not are strict - they expect all values to be strictly boolean. The symbolic operators - &&, || and ! - operate on the "truthiness" instead of strict booleans.

Because all booleans operators are short-circuiting they will actually only check the first argument for being strictly boolean, but I discourage using them with non-booleans.

Upvotes: 2

NoDisplayName
NoDisplayName

Reputation: 15736

From the docs:

Elixir also provides three boolean operators: or, and and not. These operators are strict in the sense that they expect a boolean (true or false) as their first argument:

iex> true and true
true
iex> false or is_atom(:example)
true

Providing a non-boolean will raise an exception:

iex> 1 and true
** (ArgumentError) argument error: 1

So that's to answer why it raises.

In order to do what you want, you need to use the && operator, so it would be

"true" && true

and again, a quote from the docs:

Besides these boolean operators, Elixir also provides ||, && and ! which accept arguments of any type. For these operators, all values except false and nil will evaluate to true:

# and
iex> nil && 13
nil
iex> true && 17
17

Upvotes: 0

Related Questions