Loop the Loop

Our programs have come a long way. Would you believe that a few lessons
ago we were examining the semicolon after a line; now our programs can
determine what actions to take based on criteria that we've only begun
to explore? We've made a lot of progress, marching straight from our
humble beginnings to where we are now.

It's that straight part that we're going to rectify today. No longer
will our programs be forced to merely plow through line after line of
code, skipping comments and blocks in conditionals, never looking
back. Now we'll teach our programs how to jump around a bit, to take
their time and enjoy the code we've written, to evaluate those lines a
few times over. In this lesson, we'll examine the loop.

Loops are one of the most important structures in programming. You use
loops to build lists and to examine lists, to read input, and Cocoa
actually uses a loop to process all of the things the user is doing.
When you're programming in Cocoa, you are almost always running in a
loop.

The basic structure of a loop is very simple and is reminiscent
of the conditionals we were looking at in our last lesson. You
have a token that
identifies the type of loop you're using, a condition
that tells the loop when to stop, and a block of
code that get executed each time through the loop. These three
attributes of a loop define all the behavior that goes into the
structure, even though some of the loops treat the different parts a
little differently and some of the loop types order the parts
differently.

While you Were Looping

while loops are the simplest type of loop and the one you
will probably use most often. When you start dealing with
the Cocoa classes that represent lists and groups, you'll use while
loops coupled with NSEnumerators to process all the elements of the
list. Let's take a look at a while loop, which is wrapped up in a new
function that we can add to our program.

Let's that a look at the code before we graft this into our program.
First note that the loop code we're looking at is in a function
definition, which we recognize from lesson 2. The return
type for the function
is a new type, void. This
type is special; it means that the function returns nothing of value,
so the return should be ignored (If you try to define
a variable's
value to be the return value of a void function, you'll incur a warning
).

Now that we understand the window dressing, let's look inside the panes.
We start with a normal
variable definition, and then a printf that announces
our intent to the user. We've got a while loop, and then
a printf that announces what we've done. So what does the
while loop do, and how does it work?

It begins with a whiletoken,
then something in parentheses, and then a block of
code that defines what the computer should execute while in the loop.
The magic lies in this something in parentheses, which is the familiar
condition. The code will continue to loop while this condition is TRUE. As
long as the condition evaluates
to something besides FALSE (a.k.a.
zero), the computer will execute the loop.

The easiest way to think of this is that the computer looks at the whole
while structure as a complex line of code. When it gets
to the line, it evaluates the condition. If the condition is FALSE,
the computer moves on to the next bit of code after the
while loop. But if the condition is TRUE, it executes the
code in the block. This execution is called an iteration,
which is one pass through the loop. After the computer finishes the
block, it checks the condition again, and if it's still TRUE, it does
another iteration, over and over like this in a loop until the
condition is FALSE. So very literally, the loop is executed
while the condition is true.

The code we have in our block prints out a line of text, containing the
number it has counted to. Then it increments
the variable loopsPerformed. So each iteration through
the loop, it prints what it's counted to and counts higher. This
counting higher is called the step,
because it defines where the loop should move next as it goes along
its path from start to finish. Without a step, your loop would never
complete itself. And each iteration through the loop, the condition
checks that the number of loops we've performed is less
than or equal to (that's the '<=') the total
number of loops to perform. Our condition is TRUE as long as we're
still counting, and false as soon as we've counted higher than
that.

So let's pop our new function into our project at the end of our main.c
file. Remember to put a function
declaration at the top of the file, like this:

void countTo(int loopsToPerform);

Now, let's take out the line of code in our main function
that used to say:

printf("My favorite number is %d!", favoriteNumber);

And replace it with a line that says:

countTo(favoriteNumber);

That should put our program into a state that can run, so let it loose.
You'll see how quickly the computer can count.

Do it While You Can

There is one little thing that while does that can sometimes
be annoying: it checks the condition every time through the loop, from
first to last. This seems like it's just the way you want it, but
sometimes you want to have some code that always works once, but then
continues to work while the condition is true. For this case (which
you won't use very often), C has the
do...while loop, which looks like this:

We've changed things around a bit, but the basic structure here is similar
to the one in our last code snippet. The important changes happen
where the while loop turned into a
do...while loop. Let's look at that in more
detail.

We begin our new loop with a do token. This tells the computer
that the immediately-following block is to be executed no matter what.
After the block we find a while token, then a condition
in the normal parentheses. Note that we've switched our condition
around so that we're now checking with a greater-than
or equal-to operator (the '>='), but since we also
changed the order of the variables in the condition, it's the same
test.

Since there really isn't anything special about this type of loop, we're
going to explore a little more about loops and programming in general.
Let's start by doing something we're not supposed to (which means you
shouldn't run the following):

We've replaced our continue condition with the constant 1. This means
our loop will continue until 1 evaluates to 0, which will never
happen. This is an example of an infinite
loop. You've told the computer to continue iterating through the
loop forever, printing all the while.

You will note, as you program more and more, that the computer always
does what you tell it to very literally because it has no idea how to
take your instructions any way other than literally: it can't catch
your mistakes and won't pick up the inflection in your
voice. Programming (in
imperative languages like C and it's derivatives, at least) is the
process whereby you spell out exactly what you want the computer to do
and in what order you want the computer to do that. You tell the
computer how to do everything, from writing on the screen to writing
to a file. We're using functions like printf, a C
function, to avoid having to do some of that low-level work, by
relying on the work others have done before us because we don't want
to do what most programmers call "reinvent the wheel." If the work is
done, use it, and don't do it again. The code you write contains
loops; your development should not. Avoiding the trap that is
reinventing the wheel is called "Code Reuse," and it is very common
and a demonstration of good code design.

The power of Cocoa is that almost all of the basic tasks--and some of
the more advanced ones--are already programmed and waiting for you,
and you only have to tell the computer what to do when you're dealing
with things specific to your program. Right now we can see a glimmer
of that by noticing how much we've used printf, or how
much every Mac application uses a common Cocoa feature, a little thing
called a window.

But before we start dreaming of things to come, let's see how we can
fix our little snafu we made:

We've added in a little conditional that checks to see if we've counted
high enough, and if we have it will use the break
statement we used in lesson 3 to break
out of the switch, only now we're using it before to
break out of the loop. Whenever the computer finds a
break, it will stop iterating through the loop it's
currently in. If it's in a loop inside another loop (a nested
loop), it will break out of the deepest one. Here's another way to
stop our broken code from becoming a real problem (again, you can run
this):

Here, we added a break at the end of our loop that will pop us out, but
we also added a conditional that will fire whenever we have more
counting to do. In that conditional we use the continue
command, which puts us into the next iteration
of the loop without completing this iteration. So whenever we have
more counting to do, we skip back to the top of the block, without
hitting the break statement.

You're probably thinking that these are stupid ways to fix the problem,
and we should just use the loop's condition like we started with, and
you're right. Keep thinking of things like that and your code will be
nice and readable.

For Every Loop There is a Condition

The final loop we'll look at is the for loop. When you
want to deal with a range of numbers, for loops can be a
great timesaver. And when you're dealing with integers, you'll usually
want to use a for loop. Lets' take a look at the code we used
to demonstrate the while loop:

The basic idea of the for loop is to take code logically
related to the loop and move it into places so that it is more
visually related. The condition of a for loop thus takes
on three different duties, which we will examine in order. Each duty
has it's own section within the parentheses, which is separated from
the others by a semicolon.

The first section is for initialization. This is evaluated when the program
flow first gets to the for loop and never again (unless
the program comes upon the loop again). Here, you can give a value to
a variable that you'll use as a counter, usually using the normal
assignment operator. If you don't want to initialize any values,
just leave this section blank.

The middle section is the condition. This acts just like a while
loop's condition: the loop will continue to be executed as long as
this condition is true. Just like in a while loop, this is evaluated
every time at the beginning of the iteration to see if the loop should
be executed at all.

The last section is the step, just like
the step we saw in the while and
do...while loops. This section is evaluated
every time the loop completes an iteration,
before the condition is checked.

These three sections--initialization, condition, and step--make up
the environment that the for loop operates in. Copy this
code snippet and replace the countTo function you had,
and run the program to see that even though the code changed, the
functionality of the program didn't change at all from when we had the
while loop.

Note, however, that this isn't always the case. There are things you
can do with a while loop that you can't do with a
for loop, like take multiple actions to step to the next
iteration, or initialize multiple variables. In general, a
for loop is a less extensible solution that solves the
same problem as a while loop, but for now it's hard to
see the differences because our knowledge of variable types limits us
pretty closely to counting.

More Types That You Can Count On

We now understand the different types of loops and have a basic
idea of what their differences are. In our next lesson we'll take a
closer look at variables and introduce a few more types that will
allow us to make a better distinction between for and
while loops, as well as express a variety of new concepts
that just can't be done with integers. Although we've touched on
variables before, and used them in literally every line of code we've
written so far (well, not the lines with just brackets on them), we
really don't have much of an understanding of what these little bits
of data are or how we can interact with them. We'll look at how we
make them, where they live, and lots more in our next lesson.

Seth Roby
graduated in May of 2003 with a double major in English and Computer Science, the Macintosh part of a three-person Macintosh, Linux, and Windows graduating triumvirate.