skip to content

What does proving partial correctness of a page-draining loop leave unproven, and what closes that gap?

level: middleimportance: should knowfreq 46%

answer

  1. two claims, proved separately
  2. one is conditional on halting
  3. a spinning loop satisfies it vacuously
  4. the second needs a decreasing measure
  5. both together is total correctness

basics

~20 s

Partial correctness claims only that if the loop halts, its result meets the specification. It leaves halting itself unproven. A termination argument — a quantity that strictly decreases and cannot fall forever — closes the gap and gives total correctness.

solid answer

~40 s

Proving the loop invariant gives a conditional claim: *if* the drain loop ever exits, the sink holds exactly the records the source yields. That is partial correctness, and it is genuinely useful — it rules out wrong answers. What it does not rule out is the loop never exiting at all, because a loop that spins forever satisfies every invariant obligation vacuously: the exit case simply never arises. Closing the gap needs a second, separate argument — a **termination measure**, some quantity of the loop state that strictly decreases each pass and is bounded below, so only finitely many passes are possible. Partial correctness plus termination is **total correctness**: the loop halts, and when it does the answer is right.

go deeper

for a junior

Learn the two words and which is which: partial correctness is the conditional claim, total correctness also promises the loop ends.

for a middle

Explain why a loop that spins forever satisfies its invariant vacuously, and name the second ingredient — a quantity that strictly decreases and has a floor.

for a senior

In review, treat the two as separate questions with separate evidence, and be able to say which of them a hang or a short result set is telling you about.

for a principal

Decide where the organisation demands the stronger claim. Loops at a system boundary inherit their termination from someone else's contract, and that assumption belongs in the design, not in a comment.

## Two claims, proved separately Correctness of a loop is conventionally split into two claims because they are proved by different means and fail in different ways. - **Partial correctness**: *if* the loop terminates, the final state satisfies the postcondition. Proved from the invariant's three obligations — initialization, maintenance, and the exit step that combines the invariant with the negated guard. - **Total correctness**: partial correctness **and** the loop terminates on every input the precondition allows. The extra ingredient is a measure argument. | | Partial correctness | Total correctness | |---|---|---| | Claim | If it halts, the answer is right | It halts, and the answer is right | | Proved from | The loop invariant | The invariant plus a decreasing measure | | A loop that spins forever | Satisfies it vacuously | Fails it | | Failure looks like | Wrong or incomplete output | A hang, or a job that never finishes | ## Why a non-terminating loop is "partially correct" This is the part that reads as a trick and is not. The exit obligation has the form *invariant and not-guard implies postcondition*. If the guard is never false, that implication is never exercised; an implication with a false antecedent is true. So a drain loop that refetches the same page forever is partially correct with respect to any postcondition you like. Nothing has been proved about it because nothing was claimed — that is the honest reading of "partial". The practical consequence: an invariant review that finds nothing wrong has not told you the job finishes. Those are separate reviews. ## What a termination argument looks like You exhibit a **measure**: an expression over the loop's own state, with two properties. 1. It **strictly decreases** on every pass — not on most passes, not on average. 2. It is **bounded below**, so it cannot decrease forever. In practice the measure is an integer with a floor, which is what an interviewer expects you to produce. For the drain loop the natural measure is the number of records still beyond the cursor. Each pass appends a page and moves the cursor past it, so if every page is non-empty the measure strictly falls and cannot go below zero — finitely many passes, done. The moment a page may be empty while the cursor stands still, the measure fails property 1 and the termination claim evaporates, even though the invariant is untouched. ## The two failure modes are not interchangeable - A **partial-correctness failure** is a wrong answer: the sink is missing records, or holds duplicates. It is visible in the output, and downstream systems may act on it. - A **termination failure** is a hang: the job holds its resources and never reports. The output is not wrong; there is no output. Engineers who only ever test tend to conflate them, because a test suite that passes shows both "right answers" and "finished in time" on the inputs tested. Neither generalises. Tests sample inputs; both proofs quantify over all of them. ## Where each claim is the one you want - Loops whose measure is internal — an index walking a fixed-size collection, a window shrinking toward empty — usually make total correctness easy, and there is no reason to settle for partial. - Loops whose measure depends on something outside your code — a source that decides when the data ends — can honestly be proved only partially correct on their own. Termination there is an assumption about the environment, and it is better stated as an assumption than quietly assumed. - **Termination is not performance.** A measure that starts enormous and falls by one per pass proves the loop stops; it says nothing about whether it stops soon enough. Running time is a different question with different tools. ## Saying it in an interview Name the split, then say which half you have. "The invariant gives me partial correctness — the sink is exactly the fetched records. For termination I need the count of unfetched records to strictly drop each pass, and that holds only if every page is non-empty, so that is the precondition I would state or enforce." That answer shows both obligations and the place the second one is fragile.

  • Can a loop be totally correct with respect to one precondition and not another?
    Yes — both claims are relative to a precondition. A drain loop may be totally correct when every page is guaranteed non-empty and only partially correct without that assumption, since the measure relies on it. That is why the honest answer states the precondition rather than asserting termination outright.
  • Does proving termination say anything about how long the loop runs?
    No. A measure that starts at a huge value and falls by one each pass proves finiteness and nothing more. Termination and running time are different claims: the first is that the number of passes is finite, the second is a bound on that number. Conflating them is common and wrong.

saying these in an interview costs you the question

  • Says a loop that never halts must violate its invariant
  • Treats a proved invariant as proof the loop stops
  • Calls total correctness partial correctness plus a performance bound
  • Assumes passing tests establishes termination on all inputs
  • Thinks a loop that always halts is therefore correct