If and Cond statements
The last language features being discussed for managing Code Flow are the if
and cond
statements. The reason the if
is introduced at this late stage is to emphasize how less important it is in Elixir. The if
statement works like you might expect from other languages. However, an if
statement does not support pattern matching. By now you’ve seen that pattern matching is everywhere in Elixir! This similarity to other languages is a weakness for the if
statement.
Contents
if
statements
There are valid uses for if
conditions like needing to test a single value. Typically, if you find yourself reaching for an if
by default, realize there is probably a better way to write the code. In general, consider the writing of an if
statement as a possible anti-pattern. With that said, let’s look at the syntax and talk about how it works.
if condition do
# executed when condition is truthy
else
# executed when condition is falsy
end
A falsy value is nil
or false
and a truthy value is everything else.
If you want to test that a value is false
, you would write it as if value == false do...
A better way is to use pattern matching.
Variables and leaking
By now you’ve seen that variables bound inside a clause don’t leak out. This is also true for the if
. It is a common pattern in other languages to assign variables inside an if
statement. Beneficially, the compiler recognizes this common mistake and points you in the right direction.
# This doesn't work!
do_thing = false
if some_condition do
do_thing = true
end
#=> warning: variable "do_thing" is unused
#=>
#=> Note variables defined inside case, cond, fn, if and similar do not leak. If you want to conditionally override an existing variable "do_thing", you will have to explicitly return the variable. For example:
#=>
#=> if some_condition? do
#=> atom = :one
#=> else
#=> atom = :two
#=> end
#=>
#=> should be written as
#=>
#=> atom =
#=> if some_condition? do
#=> :one
#=> else
#=> :two
#=> end
That’s a pretty helpful error message! This shows that the if
statement returns a value and that’s how you get conditional values out of it.
Note that you aren’t able to bind multiple results like this. That is an extra signal that an if
isn’t the preferred way to manage Code Flow.
Ternary statements
In languages like Javascript, there is a ternary operator. This doesn’t exist in Elixir. However, the if
statement supports being expressed as a Keyword list putting it inline. Note that it doesn’t use the end
.
result = if true, do: "true", else: "false"
result
#=> "true"
Nested if
statements
When you see a nested if
statement, that is definitely a code smell and an anti-pattern in Elixir. This is an opportunity to refactor into one or more of the following alternative structures:
- multiple function clauses with pattern matching
- a
case
statement - possibly a
cond
statement (up next)
unless
statement
If usage of an if
clause is a code smell of a possible anti-pattern then usage of the unless
statement is even more so.
unless condition do
# executed when condition is falsy
end
The unless
clause exists, but is negative logic. This is harder to reason about and is best avoided.
No “else if” conditions
Note that the if
statement does not have an elsif
or built-in else if
style clause. If you need that, then the cond
statement is a better fit.
cond
statements
The cond
statement is well suited for replacing the if ... else if
clauses you find in many other languages. However, because Elixir provides many more powerful features for controlling Code Flow, cond
is used much less frequently.
It evaluates a series of conditions and stops at the first truthy one.
value = 123
cond do
value > 200 ->
"Greater than 200"
value > 100 ->
"Greater than 100"
value > 50 ->
"Greater than 100"
end
#=> "Greater than 100"
If nothing matches, it raises an exception.
value = 123
cond do
value in 1..10 ->
"Between 1 an 10"
value > 200 ->
"Greater than 200"
value < 100 ->
"Less than 100"
end
#=> ** (CondClauseError) no cond clause evaluated to a truthy value
To ensure something matches like the last else
clause of an if ... else if
statement, use true
as your condition.
value = 123
cond do
value in 1..10 ->
"Between 1 an 10"
value > 200 ->
"Greater than 200"
value < 100 ->
"Less than 100"
true ->
"It was something else..."
end
#=> "It was something else..."
The final true
provides a “default” or grand else
clause to ensure you have a match.
Recap
- “falsy” is when a condition is
nil
orfalse
- “truthy” is anything not falsy
if
statements do not support pattern matching- Nested
if
statements are an anti-pattern - You can do simple inline statements:
if 1 == 1, do: "One!", else: "...uh..."
- Don’t use
unless
statements. They are negativeif
statements. cond
handles theif ... else if
statements you may be familiar withcond
statements can end withtrue
to ensure a match
1 Comments
Comments are closed on this static version of the site.
Comments are closed
This is a static version of the site. Comments are not available.