skip to content

An undo stack wants an array of its edit placeholder for fast replay, so why is creating that array directly rejected?

level: seniorimportance: should knowfreq 38%

answer

  1. one side retains, the other discarded
  2. the array guards every store
  3. element type fixed at creation only
  4. the weaker allocation guards the wrong type
  5. unchecked conversion, failure at first use

basics

~20 s

An array keeps its element type while the program runs and guards every store against it, but the type argument is the one thing compilation discarded. The creation would have to record an element type that no longer exists, so it is refused.

solid answer

~50 s

The two mechanisms have opposite policies, and that is the whole answer. An array is a run-time-checked container: it records its element type when it is created and refuses a store of the wrong kind later. A type argument in a discarding model is gone by then. So a creation naming the placeholder as the element type asks the runtime to record something nobody can supply, and it is rejected at compile time. The usual escape is to allocate an array of some weaker element type and then describe it as an array of the placeholder. That compiles, with a warning that the step is an **unchecked conversion** - an honest statement that nothing verified it. The array still guards stores against the weaker type it really has, so a mismatch surfaces later, at the first use that is genuinely checked.

code

pseudocode · 6 lines
pseudocode
function makeReplayBuffer(size):
    return new array of E with length size      # rejected - E records no element type

function makeReplayBufferAnyway(size):
    raw = new array of AnyEdit with length size # the guard now watches AnyEdit
    return raw described as array of E          # accepted, verified by nothing

go deeper

for a junior

The point to carry away is the clash: an array insists on remembering what it may hold, and a discarded type argument has stopped existing, so the two cannot be combined at creation.

for a middle

Explain both halves in the right direction - the array retains and guards stores, the argument was dropped - and know that the weaker allocation plus a re-description compiles only because that step is checked by nobody.

for a senior

This is your tier's question: show where the delayed failure lands, keep the weakly typed array private to the structure, and justify each unchecked conversion at the point you write it rather than after someone debugs it.

for a principal

The call you own is the boundary policy: whether structures in your codebase may hand out containers whose guard does not match their declared element type, and what review evidence an unchecked step must carry before it ships.

## Two mechanisms with opposite policies This restriction is the clearest case in the whole subject of two designs meeting and disagreeing. Say which side does what, in this direction: - An **array** *retains*. Its element type is recorded when the array is created, travels with the value, and is consulted on every store. - A **type argument** in a discarding model is *dropped*. It is checked while compiling and then removed, and nothing at run time can consult it. One container insists on knowing its element type at run time; the other kind of type information has been deliberately thrown away by then. A creation that names the placeholder as the array's element type sits exactly on the contradiction, and the compiler refuses it rather than produce a container whose guard is a fiction. ## What array creation needs at the moment it happens Creating an array fixes three things at once: 1. **How many slots**, which the placeholder does not affect. 2. **What each slot may hold**, recorded on the array itself. 3. **What the store guard will compare against** for the rest of the array's life. Only items 2 and 3 are the problem, and they are the same fact stored once. The placeholder cannot supply it, and no later moment can supply it either - the recording happens at creation and never again. ## The escape hatch, and what it stops verifying Code that wants the array anyway allocates one whose element type is some weaker, real type, then describes that array as an array of the placeholder. This is accepted, and the compiler attaches a warning that names precisely what it gave up. | Step | What happens at run time | What is verified | |---|---|---| | Allocate with a weaker element type | the weaker type is recorded on the array | fully checked | | Describe it as an array of the placeholder | nothing at all - only the compiler's view changes | nothing: an unchecked conversion | | Store an element through that description | the guard compares against the weaker type | checked, but against the wrong thing | | Read an element and use it as an edit | the use site's own check applies | checked - and this is where it breaks | Read the warning as a statement of fact rather than as noise: *I am accepting this because it may well be right, and I am recording that I did not check it*. Treating such a warning as something to silence, rather than as a claim to justify, is what turns a local shortcut into a defect somebody else debugs. ## Where the failure actually surfaces The re-description examines nothing, so it cannot fail. The first place a mismatch is examined is a use: - A **store** that the array's own guard rejects, because the guard still compares against the weaker element type the array really has. - A **read** whose result is handed to code that expects an edit and gets something else. - A moment when the array **escapes** to a caller who was promised an array of a specific edit type and stores accordingly. The distance between the warned line and the failing line is the cost of the shortcut, and it is why the safe version of this pattern keeps the weakly typed array strictly private and converts at the boundary, where the values are individually checked. ## What to do instead The design responses are ordinary once the mechanism is clear: - Use a container that **does not retain an element check** - a list-like structure built out of a single slot type. It cannot guard a store at run time, which is exactly why it has no conflict with a discarded argument. - Keep the weakly typed array **encapsulated**: allocate it inside the undo stack, never hand it out, and convert individual elements where a real check happens. - Have the caller supply the array, since at the call the argument is still known and the creation can name a real element type. ## Why an interviewer asks this one The two earlier restrictions can be answered from a memorised rule. This one cannot, because it requires naming which side retains and which side discards, and saying it backwards is instantly visible. A candidate who says 'arrays lose their element type too' has not understood why the combination is illegal at all - if both sides discarded, there would be no conflict and no rule. The conflict exists precisely because the array remembers.

  • What exactly is the compiler telling you with an unchecked-conversion warning?
    That it has stopped checking this one step and is recording the fact. The conversion is accepted because the code may be right, but nothing verifies it, and the responsibility for the claim has moved from the compiler to you. It is an honest statement of a gap, not a suggestion to tidy something up.
  • Why does the failure show up far away from the line that was warned about?
    Because the re-description only changes how the code talks about the value; nothing is examined there, so nothing can fail there. The first examination is a real use - a store the array's own guard inspects, or a read handed to code expecting a specific edit - and that is where a mismatch finally has something to fail against.
  • Why does a list-like container built from a single slot type avoid this problem entirely?
    Because it never records an element type to guard against. It holds whatever the compiler said it may hold and performs no run-time store check, so there is nothing for a discarded argument to contradict. The trade is real: no guard means a wrong store is not caught at the moment it happens.

saying these in an interview costs you the question

  • Says arrays also discard their element type at run time.
  • Treats the unchecked-conversion warning as noise to be silenced.
  • Expects the failure at the conversion rather than at first use.
  • Thinks the array's store guard checks the placeholder's argument.
  • Claims an element type can be recorded after the array exists.