In a loop that processes a list of pending items, what does break do that continue does not?
answer
- one leaves the pass, one the loop
- where control lands afterwards
- the next condition test is the target
- remaining items: skipped or still processed
- an advance inside the body gets skipped
basics
~20 sbreak ends the loop itself: control resumes at the first statement after it. continue ends only the current pass, skipping the rest of the body and jumping to the loop's next condition test, so later items are still processed.
solid answer
~40 sBoth are forward jumps out of the middle of the body, but they aim at different targets. `break` abandons the loop entirely: the condition is never tested again, control resumes after the loop, and every item still pending is left unprocessed. `continue` abandons only the current pass: the rest of the body is skipped, the condition is evaluated again, and the next item is taken. Draining a list of pending dependencies, `break` is how you stop on a fatal conflict, while `continue` is how you skip a dependency that needs no work. The trap is a `continue` in a loop whose body itself performs the step to the next item — the jump skips that step, the condition sees the same state, and the loop never makes progress.
code
pseudocode · 7 linesi = 0
while i < count(pending):
item = pending[i]
if already_installed(item):
continue // back to the test with i unchanged
install(item)
i = i + 1 // the rest of the body - skipped by continuego deeper
Know the one-line difference cold and say where control lands: after the loop for one, at the next condition test for the other. This is a first-screen question and a vague answer reads as never having debugged a loop.
Explain the skipped-advance hang from the mechanism: the jump skips the rest of the body, and the step that makes progress was in the rest of the body. Then say where you would move that step.
Show that you audit early exits in review: every value the code after the loop reads must be set on every path out, including the one the early exit takes. That is where these bugs actually ship.
Frame it as a readability budget the team spends: each extra exit is another condition a reader must hold in mind, so a standard worth setting is that an exit must correspond to a condition someone can name in one phrase.
## Two jumps out of the middle of a body A loop body is a block that runs top to bottom and then hands control back to the loop's condition. `break` and `continue` are both **forward jumps** that leave that block early, and the whole difference between them is where control lands. - `break` leaves the **loop**. The condition is never evaluated again; execution resumes at the first statement after the loop. Whatever was still pending is left unprocessed by that loop. - `continue` leaves the **pass**. The remainder of the body is skipped and control goes straight to the loop's next condition evaluation. The loop is still alive and the next item is taken normally. Both jump forward and outward — never backward, never into the middle of some other block. That is why disciplined control flow tolerates them at all: the reader can see where each one lands without hunting for a label somewhere else in the routine, which is precisely what an unrestricted jump denies. ## Where each one lands | | break | continue | |---|---|---| | Control resumes | at the statement after the loop | at the loop's next condition test | | Condition re-evaluated | no | yes | | Items still pending | left unprocessed | processed as usual | | Natural use | a fatal conflict ends the drain | an item that needs no work this pass | | Classic failure | code after the loop reads a value this exit never set | the jump skips the step that makes progress | ## The bug continue is famous for Picture an installer walking a list of pending dependencies by index. The body reads the item at the current index, does the work, and increments the index as its last statement. Now someone adds a fast path: if the dependency is already installed, `continue`. That jump skips **the rest of the body**, and the increment is part of the rest of the body. The condition is re-tested with the index unchanged, the same already-installed item is read, the same fast path fires, and the loop spins forever. The repair is a matter of where progress lives, not of avoiding `continue`: 1. Move the step that makes progress into the loop's own header, where no `continue` can skip it. 2. Or make the body's first act consume the item — popping from a work list rather than indexing into it — so that taking the item *is* the progress. 3. Or place the skip after the progress step, so the fast path skips only the work and not the advance. The same reasoning explains why the same shape is harmless elsewhere: in a loop that pops an item off a work list at the top of the body, a `continue` further down cannot hang the loop, because the pop already happened. ## Neither jump suspends anything A common misreading is that jumping out of the body somehow puts the loop's reasoning on hold. It does not. Whatever the loop keeps true on every pass is still true at the instant either jump fires — `continue` reaches the condition with it true, exactly as a pass that ran to the end would, and `break` carries it out of the loop along with the condition that triggered it. The code after a `break` gets a different exit condition than the code after a normal exit, and it has to be written for both. That is also why the value a loop is computing must be established on **every** path out. A search loop that assigns its result only on the path that never breaks leaves the tail reading something the break path never set. ## Why the loop uses break in the first place Some loops genuinely want to test in the middle: read an item, and only after reading it can you tell whether there is anything to process. Writing that with the test at the top forces you to duplicate the read before the loop and again at the bottom of the body — the loop-and-a-half problem. A `break` in the middle removes the duplication, at the price of an exit the reader has to account for. - Reach for `break` when a condition means the loop's whole job is over or impossible. - Reach for `continue` when this one item needs nothing, and the loop's job is unchanged. - Reach for neither when the condition is really the loop's exit condition: put it in the condition, where it is visible at the top. - Never reach for either to fake a jump backwards; that is not what they do, and a loop is already the backward jump. ## What an interviewer is listening for A candidate who answers "break exits, continue skips" has the definition. A candidate who adds *where control lands* and *what the loop still owes afterwards* has the mechanism, and is the one who will spot the skipped-advance hang in review rather than in production.
- A loop pops an item off a work list at the top of the body and uses continue further down. Why does that one not hang?Because the progress step already happened before the jump. The pop removed the item from the work list, so the condition is re-tested against a smaller list and the next pass takes a different item. The hang needs a skipped advance, not a continue.
- Why does a loop whose real test sits in the middle of the body often use break?Because the value the test needs is only available after part of the body has run — you must read before you can tell whether there is anything to process. Writing it with a top test duplicates that read before the loop and again at the bottom; a mid-body break removes the duplication. That is the loop-and-a-half problem.
saying these in an interview costs you the question
- Says continue exits the loop like break, just later
- Thinks continue skips the loop's condition test as well
- Assumes an advance written inside the body still runs on continue
- Believes a jump out of the body suspends what the loop keeps true
- Treats break as returning from the whole subroutine