- Define the Basic
while...do...end
Structure - Write an Infinite Loop
- Use Control-C to Break an Infinitely Looping Program
- Terminate a
while...do...end
Loop Naturally - Use Mutating Assignment Operators (+=, -=, *=, /=)
- Terminate a
while...do...end
Loop Withbreak
Statement
The final piece of using statements to control the flow of Ruby execution is
repetition. While the default sequence requires Ruby to execute
top-down, left to right, we've seen that we can skip chunks of code using the
selection statement if...else...end
. In some ways the reverse of selection
is repetition: "Don't move on," we tell Ruby. "Instead do something else until
I say it's OK to move on." The most fundamental repetition construct, present
in pretty much every programming language, is the while...do...end
loop.
Ruby features other repetition statements, but, for the most part, they're
simplifications on the while...do...end
statement.
The basic while...do...end
looks like:
while (condition expression) do
# stuff to do
end
As long as the condition expression is true
(or truthy), the code inside the
do...end
block will run. Keep in mind, as an expression the condition
expression can be quite rich, using &&
, ||
, ()
, etc.
Given this definition of while...do...end
, any truthy expression will make
the loop run forever.
while true do
puts "say this forever..."
end
With output:
say this forever...
say this forever...
say this forever...
say this forever...
say this forever...
...
Remember truthy? Here it is again:
while -1 do # -1 is truthy....
puts "say this forever..."
end
Likewise, falsey is important as well:
while nil do
puts "I will never run"
end
If you ever run a program and it starts printing over and over without end or it never seems to finish and you're writing some looping code, you probably made a mistake and your code is stuck in an infinite loop.
Make sure you're in the terminal spot of the In-Browser IDE, and type Control-C. That's an old-school UNIX key-combination that means INTERRUPT. Interrupting a running program will break it out of an infinite loop.
Most loops aren't meant to run infinitely. There's some condition that they
cross, captured in the condition expression, that tells the while...do...end
that its time is over and it's time to return to the default sequence. Once that happens, Ruby continues executing the code after the while loop's end
.
So, somehow we need to create an expression that's true when the while
begins
(so that the code in the do...end
runs), but that eventually becomes
false.
Here's a simple example:
count = 0 # A bit of data defined outside the loop
while count < 3 do # A Boolean expression using the bit of data
puts "I am the #{count}, I love to count!" # Work
count = count + 1 # A bit of work that moves the bit of data closer to being false
end
In the line count = count + 1
, we are assigning a new value to the count
variable, where the new value is the current value plus 1.
The code above produces:
I am the 0, I love to count!
I am the 1, I love to count!
I am the 2, I love to count!
Let's say we forgot the line count = count + 1
. Our condition expression
would then always be true
and we'd have an infinite loop.
Let's look back at that previous example to notice how we're moving from a true or truthy statement to a false or falsey statement. Within each loop, the following code is executed:
count = count + 1
which slowly moves count
to a place where it is no longer less than 3, thus
ending the loop.
But writing count = count + 1
is a bit long-winded (although very explicit;
sometimes a few extra keystrokes can save you headaches with debugging,
especially when you're first learning to code). This pattern of "incrementing" a
variable is very common, so Ruby includes a shorthand for it. It's like a
contraction in conversation: very few English speakers say "can not," "have
not," or "would not" all the time. You're likely to hear them use
contractions (from the Latin: "pulling together") like "can't," "haven't," and
"wouldn't." In the code below, we are combining (or contracting) the addition
and assignment with a single operator, +=
:
count += 1 # take the value of count, add one to it and then re-assign that result to count
Unsurprisingly -=
does the reverse of +=
: it "decrements" the variable's
value and re-assigns the new value to the variable. Multiplication and division
are also supported *=
and /=
. There's even modulo-assignment with %=
,
should you need it!
Try out using these to shorten loops.
Programmers consider it most "expressive" to put the condition expression
next to the while
. Programmers are used to looking to the right of the
while
to find out why a loop exited. They understand this "why" by
understanding the condition expression. However, we can break out of a
loop by using the break
statement.
The while
should cover the general case including when to repeat and when
to finish. A break
is for priority or anomalous interruption. For example,
most TV or radio stations have a loop of programming that they run every day.
But in the case of a special alert bulletin (dramatic weather, emergency, etc.)
they can "break" out of their regular loop. The break
statement is like
this.
In the code below, our general intention is to move through the numbers 0
through 9
. That's what the while
's condition expression communicates.
However, there's a little bit of dynamite inside the code. If we just so
happen to hit magic_exit_number
, we break out of the loop early.
LEARNING NOTE: Here we're using a statement modifier and an equality-testing (Boolean) expression. All of our lessons are starting to work together!
magic_exit_number = 7
count = 0
while count < 10 do
break if count == magic_exit_number
puts "I am the #{count}, I love to count!" # Work
count = count + 1
end
Or, imagine you had a random number generator between 0
to 9
(which you'll
learn to make soon). You could assign that random number to magic_exit_number
and your repetition would vary between runs of the same program.
Note that the break
isn't necessary in the code above. We can instead refactor to keep the condition expression all in one place:
magic_exit_number = 7
count = 0
while count < 10 && count != magic_exit_number do
puts "I am the #{count}, I love to count!" # Work
count = count + 1
end
Build a while...do...end
loop that counts from 10
down to 1
, outputting
the current value during each loop. After 1
is displayed, output
Happy New Year!
. When completed, your code should produce the following:
10
9
8
7
6
5
4
3
2
1
Happy New Year!
Code your solution in lib/count_down.rb
. Use the earlier examples to put
together a solution and run learn
to see your progress.
This challenge is a slight modification of the examples we've seen. Instead of counting up in a loop, we need to count down. First, we'll need to set up the loop:
while (condition) do
end
Then we will need to set up the loop condition. In our case, we want to output
from 10
down to 1
, so it makes sense here to create a variable, assign it to
10
, then set the loop to run as long as the variable is greater than or equal
to 1
. In the loop, we will need to subtract 1
from the variable so that the
loop eventually ends.
count = 10
while count >= 1 do
count -= 1
end
We've got the loop designed. Now we just need to add the outputs. First, we want
to output the current value of count
on each loop:
count = 10
while count >= 1 do
puts count
count -= 1
end
Then, since we only need to announce Happy New Year!
at the end, we can place it
after the loop:
count = 10
while count >= 1 do
puts count
count -= 1
end
puts "Happy New Year!"
Run the tests to confirm your solution then run learn submit
to submit your
work.
Congratulations. You now have the while...do...end
construct as an ally.
With an understanding of sequence, selection and now repetition on top of
your experience with expressions, you can write powerful programs! Be sure and
experiment with writing your own loops and don't forget, if your application is
not responding, you can use Control-C to interrupt the program!