Booleans
Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.8.0", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"},
{:visual, github: "brooklinjazz/visual"}
])
Navigation
Setup
Ensure you type the ea keyboard shortcut to evaluate all Elixir cells before starting. Alternatively you can evaluate the Elixir cells as you read.
Review Questions
Upon completing this lesson, a student should be able to answer the following questions.
- What are booleans, and what information might they represent in a program?
- What are the boolean operators, and what do they do?
- What are strict vs non-strict boolean operators?
-
What are
ifstatements, and how are they useful in our programs?
Booleans
Booleans (BOO-LEE-ANS) are true and false values in your code. They are often useful for
representing conditions and triggering actions in your program.
true
false
As part of programming, you’ll often create branching paths. Essentially there are multiple things that could happen depending on certain conditions. We often call this control flow.
Let’s take an example and say we have a program that controls a light.
Either we can tell the light to power on or power off. In this case, on would be true and off would be false.
flowchart LR
A[is_powered] --> true --> on
A[is_powered] --> false --> off
Your Turn
In the Elixir cell below, turn the power on in our light control program to see the light turn on! Replace false with true.
power = false
content = if power, do: "/images/on.png", else: "/images/off.png"
Kino.Image.new(File.read!(__DIR__ <> content), :png)
For more on booleans consider this video by Crash Course Computer Science.
YouTube.new("https://www.youtube.com/watch?v=gI-qXk7XojA")
Boolean Operators
Using the boolean operators and, or and not we can compare and manipulate booleans.
and: Check If Two Booleans Are true.
Returns true if left and right-hand side are true. Returns false if either the left side and/or right side of the operator are false.
flowchart LR
A[true] --> C
B[true] --> C
C[and] --> D[true]
true and true
true and false
false and true
false and false
or: Check If One Or More Booleans Are True.
Returns true if either the left side or the right side of the operator are true.
flowchart LR
A[false] --> C
B[true] --> C
C[or] --> D[true]
true or true
true or false
false or true
false or false
not: Flip A Booleans Value
Flips false -> true and true -> false.
not true
not false
Strict and Non-Strict Operators
and, or, and not are strict boolean operators, meaning they should only be used with booleans, otherwise they will raise an error.
1 and 1
Sometimes we want to make logical comparison using truthy and falsy values. nil and false are falsy values, and everything else is a truthy value.
We can use non-strict boolean operators && (and), || (or), and ! (not) to work with truthy and falsy values.
&& Check If Two Values Are Truthy.
Returns the right-hand side value if the left-hand side value is truthy.
1 && 2
Returns the left-hand side value if it is falsy.
nil && 2
false && 2
|| Checks If One Or More Values Are Truthy.
Returns the first truthy value on either the left-hand side or the right-hand side.
2 || nil
1 || 2
nil || 2
!: Flips the Falsy Or Truthy Value to true Or false.
Flips truthy -> false and falsy -> true.
!1
!nil
When Should You Use Strict Or Non-strict Operators?
You might wonder why you shouldn’t simply always use non-strict operators &&, ||, and ! since they also work with booleans.
true && true
false || true
!true
The primary reason is communication. We want our code to communicate to other developers, so it’s useful to use and, or, and not to communicate to other developers reading our code that we are working with boolean values.
Generally, prefer and, or, and not with booleans, and use &&, ||, and ! with non-boolean values.
Control Flow
By comparing booleans, you can create branching paths in your code depending on certain conditions.
For example, let’s say we’re building a weather app. This app might send morning notifications to users to let them know that it’s going to be a sunny day.
You might check that the user is subscribed, that it is morning, and that it is sunny. If all of these things are true, then we want to send a notification.
flowchart LR
A[is subscribed] --> and
B[is morning] --> and
C[is sunny] --> and
and --> true
true --> D[send notification]
and --> false
false --> E[don't send notification]
We can cleverly use boolean operators to write this logic. Try changing any of the true values to false and you’ll see we no longer simulate sending a notification.
is_subscribed = true
is_morning = true
is_sunny = true
is_subscribed and is_morning and is_sunny && "send notification!"
if
Rather than rely on boolean operators entirely, it’s more common to use specific control flow structures. For example, we can replicate the code above using if statements.
if is_subscribed and is_morning and is_sunny do
"send notification"
end
else
if statements allow use to trigger some code when some condition is truthy. We often use if statements in combination with else statements to create two separate branching paths in our code.
For example, let’s say we’re creating a coin flip game. The user provides a guess of :heads or :tails, and we have coin flip of :heads or :tails.
flowchart LR
if/else --> c[coin == guess] --true--> w[You win!]
c --false--> l[You lose!]
Here’s how we could write this in code. Try changing guess to :heads to win the coin flip game.
coin = :heads
guess = :tails
if coin == guess do
"You win!"
else
"You lose!"
end
Further Reading
Consider the following resource(s) to deepen your understanding of the topic.
Mark As Completed
file_name = Path.basename(Regex.replace(~r/#.+/, __ENV__.file, ""), ".livemd")
save_name =
case Path.basename(__DIR__) do
"reading" -> "booleans_reading"
"exercises" -> "booleans_exercise"
end
progress_path = __DIR__ <> "/../progress.json"
existing_progress = File.read!(progress_path) |> Jason.decode!()
default = Map.get(existing_progress, save_name, false)
form =
Kino.Control.form(
[
completed: input = Kino.Input.checkbox("Mark As Completed", default: default)
],
report_changes: true
)
Task.async(fn ->
for %{data: %{completed: completed}} <- Kino.Control.stream(form) do
File.write!(
progress_path,
Jason.encode!(Map.put(existing_progress, save_name, completed), pretty: true)
)
end
end)
form
Commit Your Progress
Run the following in your command line from the curriculum folder to track and save your progress in a Git commit.
Ensure that you do not already have undesired or unrelated changes by running git status or by checking the source control tab in Visual Studio Code.
$ git checkout -b booleans-reading
$ git add .
$ git commit -m "finish booleans reading"
$ git push origin booleans-reading
Create a pull request from your booleans-reading branch to your solutions branch.
Please do not create a pull request to the DockYard Academy repository as this will spam our PR tracker.
DockYard Academy Students Only:
Notify your teacher by including @BrooklinJazz in your PR description to get feedback.
You (or your teacher) may merge your PR into your solutions branch after review.
If you are interested in joining the next academy cohort, sign up here to receive more news when it is available.
Up Next
| Previous | Next |
|---|---|
| IO | Comparison Operators |