skip to content

Inside a generic undo stack, why can the body not construct a fresh value of its own type placeholder?

level: middleimportance: must knowfreq 55%

answer

  1. the body is compiled once
  2. creation needs a concrete type
  3. the site must pick an initialisation
  4. the discarded argument cannot supply it
  5. and nothing promises it is buildable

basics

~20 s

Construction has to name a concrete type at the point it happens: what to allocate and how to initialise it. A placeholder names none of that once the argument is discarded, and nothing promises the argument can be built at all.

solid answer

~50 s

A construction site is a decision taken in the compiled body: allocate this much, run this initialisation. The body of a generic undo stack is compiled once and shared by every argument, and in a discarding model the argument is not present at run time to make that decision - so the site has nothing to build. There is a second, independent gap that people forget: even a platform that keeps arguments available would still need a promise that the placeholder's argument *can* be built the way this site wants. A limit on a placeholder constrains what you may call on a value of it; on its own it does not guarantee a way to produce one. Storing, returning and passing along a value of the placeholder stay legal, because none of them decides what to create.

code

pseudocode · 8 lines
pseudocode
type UndoStack<E>:
    items = empty list

    function push(edit):
        append edit to items          # fine - the caller already built it

    function makeBlankEdit():
        return construct E()          # rejected - E names no concrete type here

go deeper

for a junior

Hold on to the one-line version: making a value requires knowing which type to make, and a placeholder is not a type yet. Storing a value someone else made is a different act and stays allowed.

for a middle

This is your tier's question. Explain that one compiled body is shared by every argument, so the creation site has no type to name, and be ready to say which operations on the placeholder remain legal and why.

for a senior

Demonstrate the second gap: even with arguments available at run time, a creation needs a promise that the type is producible. Then show the design move - stop making the generic body responsible for producing values it was never given.

for a principal

The call you own is where value production belongs in a layered API: bodies that manufacture values of their own placeholder push a requirement onto every future argument, which quietly narrows who can use the abstraction at all.

## What a construction site must decide Creating a value is not one act but three decisions, all taken at the point in the code where the creation is written: 1. **Which concrete type** is being made - the thing that fixes the layout and the size of what is allocated. 2. **Which initialisation** to run, since a type may offer several ways to be built, or none that takes no arguments. 3. **What the result may be treated as** afterwards, which the surrounding code has already fixed. A **type placeholder** is a name that stands for whatever argument a caller supplies. In the body of a generic undo stack it is a promise about *some* type, and a construction site needs *the* type. That mismatch, not a style rule, is what the compiler reports. ## Why one shared body cannot supply it In the model this leaf is about, the compiler produces **one body** for the generic declaration and every argument runs through it. That is exactly why the declaration is cheap; it is also why it cannot construct. - The allocation instruction in that shared body would have to name a type, but the body is the same one whether the stack holds text edits or style edits. - The type argument that would have settled the question was **discarded at compile time**; nothing at run time can be consulted to recover the choice. - A caller's argument is known at the *call*, not inside the shared body, and the body is what contains the creation. Under a compilation strategy that generates a separate body per argument, this first gap simply is not there - each generated body knows its own type. That is a different strategy with a different price, and it is a neighbouring subject; the point here is that the restriction follows from the loss, not from generics as such. ## The second gap, which survives even when the first closes Suppose the argument *were* available while the program runs. The site still has to know that the type can be built the way it intends. | What the site needs | Where it would come from | Supplied by a discarded placeholder? | |---|---|---| | The concrete type to allocate | the type argument, at run time | no - it was discarded | | A way to build it with no inputs | a constraint on the placeholder | no - a limit constrains use, not creation | | The initialisation to run | the chosen way of building | no - follows from the two above | This is why the honest answer is 'two gaps, not one'. A placeholder limited to some family of edits promises that every argument *is* an edit, so the body may treat values as edits. It does not promise that every argument can be produced out of nothing: an argument may require inputs the generic body knows nothing about, or may deliberately have no publicly reachable way to be built at all. ## What is still legal in the same body The restriction is narrow, and naming its edges is what shows you derived it: - **Storing** a value the caller passed in - nothing is created, only moved. - **Returning** a value of the placeholder that came from somewhere else. - **Comparing, counting, reordering** the values already held. - **Building the container itself** - the stack, the list of slots - as long as no value *of the placeholder* is created. The pattern is consistent: any operation that merely moves or inspects an already-built value is fine, and only the act of deciding what to allocate is refused. ## Reading the error as a derivation When a compiler refuses a creation of the placeholder, read it as a sentence about missing facts: *at this point in the compiled code, I do not know what to allocate, and nothing you declared promises it could be allocated*. Candidates who have only memorised the rule state it as a prohibition and stop. Candidates who have derived it can immediately answer the two follow-ups that matter - why storing is still fine, and why knowing the argument at run time would not by itself be enough. That difference is precisely what the question is asked to find. ## The undo stack, concretely An undo stack that wants to seed itself with a blank edit, or to manufacture a placeholder value to fill an empty slot, runs straight into this. The design response is to stop making the body responsible for producing values at all: the stack holds what it is given and reports emptiness as emptiness, rather than inventing a value it has no way to construct.

  • Would keeping type arguments available at run time, by itself, make the construction legal?
    Not on its own. It closes the first gap - which type to allocate - but the site still needs a promise that the argument can be built the way it wants. Without a constraint that guarantees an available way to construct, a platform that knows the argument would still have to refuse, because the type it now knows may have no such way.
  • Why is storing a value of the placeholder legal when creating one is not?
    Storing only moves a value the caller already produced; the body never decides what to allocate or how to initialise it. Creation requires naming a concrete type at the site itself. The dividing line is not how the value is used but whether the shared body has to choose what comes into existence.
  • Does the restriction change if the placeholder is limited to a family of edits?
    Not for creation. A limit tells the body what it may do *with* a value of the placeholder - which operations are available on it - and that is a claim about use. Being an edit does not imply being producible with no inputs, so the limit leaves the construction site exactly as short of facts as before.

saying these in an interview costs you the question

  • Says every placeholder has a default way to be built.
  • Believes any upper limit on a placeholder supplies a way to construct.
  • Confuses creating a value with storing one the caller passed.
  • Calls the rule a style restriction rather than a missing fact.
  • Assumes allocation inside any generic body is banned outright.