- 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, "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, that's captured in the condition expression that tells the
while...do...end
that it's time is over and it's time to return to the
default sequence which will resume after the 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
This 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 always be true
and, therefore, 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. With each loop, the following expression is evaluated:
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 clear, sometimes
a few extra keystrokes can save you headaches with debugging if you aren't too
clever about saving a few keystrokes). This pattern of making a change to the thing
that you want to assign to update or "mutate" is very common. Ruby has a shorthand
for this. 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." So we can link addition and assignment, like above, with:
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 does a reduction of the variable's
value and re-assigns it 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.
LEARNING NOTE: In the code below we're using a statement modifier and an equality-testing (Boolean) expression. All of our lessons are starting to work together!
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.
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.
Again, another way of writing this that keeps the condition expression all in one place would be:
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 know 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, use Control-C to interrupt the program!