Nick,
The actual answer is maybe the reverse of your intuition: a while
loop can be used anywhere a for
loop can, but not vice-versa.
To see why, imagine two cases:
A. An array/list traversal (a “traversal” means, “a walk down every element”). This is the quintessential case for the for
loop.
let stuff = [1,2,3,4,5]
for item in stuff {
print(item)
}
However, you can write this same function with a while
loop easily:
let stuff = [1,2,3,4,5]
var index = 0
while index < stuff.count {
print(stuff[index])
index += 1
}
this has exactly the same results. The only difference is that you have an extra variable index
—but you may notice a similar variable (pointing straight at the item rather than at its element index number) in the for
loop. The index
variable hangs around after the while
loop where the item
variable disappears, but otherwise these two snippets of code are exactly the same.
B. On the other hand, there are things you can do with while
loops you can’t do with for
loops. I won’t write actual Swift code here because there’s not something simple enough you’re already necessarily familiar with, but consider this algorithm:
while a file is still downloading:
animate the progress spinner
Since you have no idea when the file will finish downloading, you can’t use a for
loop. (Well, you can, and I’ll mention why at the end of this post, but you can’t without special help.) These types of loops are often called “poll loops” or “event loops” and they’re found everywhere in real-life programming, especially in networking or app UI programming.
There’s a final common case of while
that for
cannot cover: the infinite loop. That’s a term I’m sure you’ve heard before, but I think non-programmers aren’t aware that it’s not a name for a bug, but actually a very common construct in real programming. Why? There are lots of reasons you might want an infinite loop. Here are just two of them:
- An operating system that runs a computer has, as its primary operating instruction, a loop of “check what I need to do and do it”. This loop is infinite because until you shut down or power is lost it must keep going, forever.
- An event loop for an application often will consist of an infinite loop, because any number of things—selecting a Quit command, pressing ⌘Q, another program requesting it, or the system shutting down—might be the reason the program will end, but otherwise the program continues indefinitely. (Both the
for
and the while
loops have ways to “break out” early if necessary, and that’s the only way you ever get out of a true infinite loop.)
In Swift, you can create an infinite loop by writing while true
. Which means, since while
checks the truth of its condition, “while true
is true”—in other words, “always and forever”, so you get an infinite loop! But don’t try that in Swift Playgrounds until you’ve learned how to break out of loops—otherwise, you may have to force-quit Playgrounds. Real infinite loops almost always have a “sleep” function inside them to wait a period of time, or a “poll” function to wait until a certain thing happens. If they didn’t, the computer could grind to a halt, just looping forever!
(On iPad, the iPadOS doesn’t let a single app get out of hand like that—it basically says “okay, you’ve had enough now, let another app have its turn”, but the app—such as Swift Playgrounds—may itself lock up. On traditional computers such as macOS, though, an infinite loop without a wait absolutely will grind your computer to a halt and may require a hard-reset.)
Before your brain breaks too much I’ll mention that in the 21st century, a concept called the iterator has become pretty much an expected part of every programming language, and it allows for
loops to do many things that previously could only have been done with while
loops, and to do them with less room for error by the programmer (the type that might lead to an inadvertent “spinning” into an infinite loop) than a while
loop allows. For example, an iterator might be connected to a clock myClock
such that it ‘ticks’ every second returning the current time, and then you could write:
for time in myClock {
print("It is now", time)
}
Because myClock
is an iterator, it will naturally just stop at each run of the for
loop until the next second has arrived. This would more “naturally” have been written with a while
loop in older programming languages before the concept of iterators caught on. The “animate the progress spinner” example above could similarly be done with an iterator that checked the download progress and a for
loop.
And, as it turns out, the for
loop in the first code snippet above used an iterator—one Swift provides to all array/lists, that returns each item sequentially. The 20th-century way to traverse a list without an iterator would be something more like
for index in 0..<stuff.count {
print(stuff[index])
}
—and back then, the index
variable would have been called “the iterator”!
Because of the flexibility of iterators, several of the very newest programming languages (not Swift, but in the same generation) have jettisoned the while
loop entirely, and now only have two kinds of loops, the for
loop and an infinite loop, often called just loop
. So your intuition wasn’t actually that far off—for the 21st-century programmer, anyway!