skip to content

A buffer declared inside a section block is stored in a document that outlives it: what ends when the block exits?

level: juniorimportance: should knowfreq 52%

answer

  1. one ends, the other need not
  2. text region versus time interval
  3. the name goes, the value may stay
  4. an escaping reference outlives the block
  5. in scope is not a promise of a value

basics

~20 s

Only the name's scope ends. Scope is the region of program text where a name can be used; lifetime is the stretch of run time during which the value exists, and the document's reference keeps that value alive.

solid answer

~40 s

Two different things are being confused when this is answered badly. **Scope** is textual: it is the region of the program in which the name `buffer` can be written and resolved, and that region stops where the block stops. **Lifetime** is temporal: it is the interval during which the value behind the name still exists and can be used. Attaching the buffer to the document makes something outside the block refer to it, so the value goes on living after the block exits even though nothing can name it as `buffer` any more. The reverse can happen too: a name can stay in scope over a stretch where the value behind it has already been released or replaced. Scope tells you where you may write a name, never what is behind it.

code

pseudocode · 9 lines
pseudocode
declare report = new_document()

for each section in sections
    declare buffer = new_buffer()
    fill(buffer, section)
    report.attach(buffer)   // the value escapes the block

// the name 'buffer' cannot be written here - its scope ended
render(report)              // yet every buffer is still alive

go deeper

for a junior

Give both one-line definitions and keep them apart: scope is where a name can be written, lifetime is how long a value exists. One sentence each is enough at this stage.

for a middle

Produce the asymmetry without prompting - a value outliving its block through an escaping reference, and a value dying while its name is still perfectly in scope.

for a senior

Tie it to a real failure: a reference that escaped a block and kept a large structure alive, or a mention of a name still in scope after the thing behind it was released.

for a principal

Set the convention that decides ownership at block boundaries, so that whether a value may escape is stated in the design rather than discovered from a leak report.

## Two questions that sound like one When a declaration appears inside a block, it answers two questions at once, and interviewers separate them deliberately: - **Where may this name be written?** That is the declaration's **scope** - a region of program text, fixed when the program is written, delimited by the block that contains the declaration. - **How long does the value last?** That is the value's **lifetime** - an interval of run time, starting when the value is created and ending when it is released or becomes unreachable. Scope is a property of a *name*. Lifetime is a property of a *value*. Block structure ties them together in the common case, which is exactly why the two get conflated: a scratch counter declared in a loop body is unnameable after the loop and its value is worth nothing afterwards, so the same block boundary appears to end both. ## The case where they come apart The renderer case pulls them apart. A section block declares a buffer, fills it, and attaches it to a document that is itself declared further out. At the block's exit: - the name `buffer` leaves scope - a later line that writes it is ill-formed, and a new iteration's declaration is a *different* binding; - the value does not leave anything - the document holds a reference to it, and rendering the document later reads exactly those bytes. The block exit ended the **only convenient way to name** the value. It did not end the value. | | scope | lifetime | |---|---|---| | belongs to | a name | a value | | kind of thing | region of program text | interval of run time | | decided by | block nesting, before the run | creation and release or unreachability | | ended by | the end of the enclosing block | release, or nothing referring to it | | can outlast the other | no | yes, whenever a reference escapes | ## The other direction, which candidates forget It is equally possible for the value to die while the name is still in scope: 1. A handle is declared near the top of a routine and released explicitly halfway down. The name is in scope to the end of the routine, and every mention after the release is a defect the text does nothing to flag. 2. A binding is overwritten with a fresh value. The name is in scope throughout; the *first* value's lifetime ended at the overwrite if nothing else referred to it. 3. A value is moved or handed to an owner that immediately releases it. The name still resolves, and the thing behind it is gone. So "in scope" is not a promise that there is anything usable behind the name. That single sentence is the payoff of the whole distinction. ## What decides a lifetime, since the block does not Once a reference escapes its block, the block's exit stops being the deciding event. What replaces it differs by design, and a candidate should say that it differs rather than assert one answer: - Some systems end a value's lifetime automatically once nothing can reach it any more, so the escaped buffer lives exactly as long as the document that holds it. - Some require an explicit release, so the escaped buffer lives until someone releases it - and leaks if nobody does. - Some tie the lifetime to a declared owner and check statically that no reference outlives it, so the escape has to be spelled out before it is allowed. In all three, the block exit is a **scope** event. It is not what decides the lifetime. ## Saying it well in an interview A strong answer names both terms, gives each a one-line definition that could not be mistaken for the other, and then produces the asymmetry unprompted: - the value can outlive the scope, whenever a reference escapes into something longer-lived; - the value can die inside the scope, whenever it is released or replaced; - therefore the block boundary is a statement about **names**, and any claim it makes about storage is incidental. A weak answer collapses the two into "the variable is destroyed at the end of the block", which is wrong in both directions at once and predicts a defect that will not happen and misses one that will.

  • Can a value's lifetime end before the name's scope does?
    Yes, and it is the half people forget. A handle declared at the top of a routine and released halfway down leaves the name in scope for the rest of the routine with nothing usable behind it. Overwriting a binding does the same to the value it previously held. Scope says where a name may be written, not what it currently denotes.
  • What decides how long the escaped buffer actually lives?
    Whatever still refers to it. Once the document holds the buffer, the buffer lasts at least as long as the document's hold on it does; the block's exit only ended the ability to reach it by that name. The deciding event moved from the block boundary to the owner that took the reference.

A visitor badge stops opening doors the moment you leave the building, but the package you handed to reception is still sitting there. The badge is the name's scope; the package is the value's lifetime.

saying these in an interview costs you the question

  • Says the value is destroyed the moment the block ends
  • Uses scope and lifetime as two words for one idea
  • Thinks a name still in scope guarantees a usable value behind it
  • Believes storing a reference elsewhere widens the name's scope too
  • Assumes block exit is what decides when storage is reclaimed