Replacing a jump out of a step sequence with a boolean flag tested by every later step — why can that be worse than the jump?
answer
- one decision, written many times
- state the reader carries onward
- reached and skipped, not unreached
- more than one writer again
- guard one region, not N statements
basics
~20 sThe jump said once where control went; the flag says it everywhere. It adds a mutable value that every later step reads, so the reader must now track extra state through the whole routine to know which statements actually run.
solid answer
~50 sThe jump had one virtue worth keeping: it was a single, visible statement saying control leaves here and arrives there. Replacing it with a flag distributes that one decision across every statement below. Three things get worse. The **state a reader tracks grows** — every later step now depends on a variable written somewhere above it, which is the same read-at-a-distance coupling the jump had, minus the visible arrow. The **invariant weakens** — instead of `the steps below did not run`, you get `each step below ran its test and did nothing`, which is a different claim and easier to get wrong. And the flag **can be written from more than one place**, so the set of predecessors that decided the outcome is once again open. A keyword ban that produces this has moved the defect, not removed it.
code
pseudocode · 11 linesfailed = false
if not open_device() then failed = true end
if not failed then
if not write_image() then failed = true end
end
if not failed then verify() end
if failed then report() endgo deeper
Recall the trade being made: a jump is one statement, while a flag is one assignment plus a test on every step after it. More places to get wrong, not fewer.
Explain the reader cost precisely — a variable carried to the end of the routine, an invariant spread over N guards, and several possible writers — and name the fix as one guarded region.
Demonstrate that you can price the alternative honestly: the single-region rewrite duplicates the failure tail or deepens nesting, which is why a shared tail survives in real cleanup code.
The judgment worth having is what your standard actually rewards. A keyword ban scores this refactor as an improvement while the routine got harder to change, so the rule has to be written about the defect.
## What the jump was actually saying A forward jump out of a step sequence encodes one fact in one place: *from here, the remaining steps do not run, and control continues at the tail*. Whatever else is wrong with it, that fact is written down once, at the point where the decision is made, and a reader who sees it knows what follows. When a rule bans the keyword rather than the defect, the usual substitute is a flag: a boolean set where the jump used to be, and tested by every statement that used to be skipped. ## What the flag adds 1. **State that every later step reads.** Before, a step's behaviour depended on its own inputs. Now it also depends on a variable assigned somewhere above it. The reader's working set grows by one variable for the rest of the routine, and that variable's value at any point depends on a history the text does not show — which is the original complaint about jumps, restated. 2. **A weaker and less obvious invariant.** `Nothing below runs` is a strong, checkable claim. `Each step below runs its guard and then does nothing` is a claim about N guards, and it is only true if every one of them was written. The classic defect is the step somebody adds later without the guard. 3. **An open set of writers.** The jump had one site. A flag can be set in three places and cleared in a fourth, and now the question *why did step five not run* requires scanning every assignment to it. 4. **Noise proportional to the number of steps.** Each remaining step carries a test that says nothing about that step's own job. ## The two shapes, side by side | Property | Forward jump to the tail | Failure flag on every step | |---|---|---| | Where the decision is written | One statement | One assignment plus N tests | | Statements below the decision | Not reached | Reached, then skipped individually | | Reader's extra state | None after the jump | One variable to the end of the routine | | Sites that can change the outcome | The jump site | Every assignment to the flag | | A step added later | Placed after the tail, unaffected | Silently runs unless someone adds the guard | ## The honest rewrite The fix is not to make the flag nicer. It is to **guard the skipped work once, as one region, instead of guarding N statements separately**. If steps two, three and four must not run after step one fails, then those three statements belong inside one selection arm — a single decision, a single region, and no variable surviving past it. That rewrite has a real cost, and you should say so rather than pretend otherwise. With several fallible steps in a row, nesting each inside the success arm of the previous one either **duplicates the failure tail** in each alternative arm or **deepens the routine by one level per step**. That cost is exactly the pressure that keeps a forward jump to a single shared tail alive in cleanup code: the jump buys one copy of the tail at no nesting cost. Which tradeoff wins depends on how many steps there are and whether the language binds release to leaving a block. ## Where a flag is genuinely the right answer Not every boolean is this defect. A flag is fine when it is **data that outlives the decision** rather than a stand-in for control transfer — a result the caller inspects, a status recorded for reporting, a mode chosen once and read by an explicit dispatch. The test that separates the two: if removing every later guard and moving the guarded work into one region would produce identical behaviour, the flag was a disguised jump. If the value is genuinely consulted at points that are not simply *the statements after the decision*, it is state. ## The interview point This question is asked because it distinguishes a candidate who learned a rule from one who learned a reason. The rule says avoid jumps; the reason says avoid a target with an open predecessor set and a reader obligation that grows with the routine. The flag passes the rule and fails the reason, and being able to say that in one sentence is the whole answer.
- How do you tell a disguised jump from a flag that is genuinely data?Ask what reads it. If the only readers are the statements that immediately follow the decision, and moving that work into one guarded region would behave identically, it was control flow written as a variable. If it is consulted later at points that are not simply the tail of the sequence — a reported status, a mode an explicit dispatch selects on — it is state.
- What is the specific bug that appears when a step is added to a flag-guarded sequence?The new step runs after a failure. The invariant held by the old code was really N separate guards, so adding an unguarded statement breaks it silently, with no compiler or reviewer signal. A single guarded region has no such failure mode: new work placed inside the region inherits the guard.
- Does the same objection apply to a flag used to leave a loop early?The mechanism is the same — a variable standing in for a control decision — but that particular case belongs with iteration and its exit constructs. The part that is this subject is the general shape: when the flag's only job is to say the following statements should not run, it is a jump written as data.
saying these in an interview costs you the question
- Assumes any flag-based version is structured because no jump appears
- Says the flag is safer because control never leaves the sequence
- Misses that the guarded statements are still reached and tested
- Thinks renaming the flag addresses what is wrong with it
- Claims nesting the steps removes the flag at no cost