skip to content

Generic Programming

Code written once against a placeholder type instead of a concrete one: parameters, bounds, variance, erasure and specialization. Interviewers use a generic signature to test type-system depth.

on this pageshow

explore

questions

95 · 6 sections

A connection type carries a message-type placeholder and a standalone helper carries its own - how long is each fixed?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A placeholder introduced on the type is chosen once when an instance is created and every member of that instance shares it. A placeholder introduced on one operation is chosen afresh for each call and is scoped to that call.

open as a page

When a generic filter helper is called without an explicit type argument, what does the compiler use to fill its placeholder?

level: juniorimportance: must knowfreq 58%
basics
~20 s

The compiler solves the placeholder from evidence at the call site: the static types of the arguments, the type the result is expected to have where the call sits, and any bound or default declared on the parameter itself.

open as a page

Why is a routing registry that maps route keys to handler payloads declared with two placeholders rather than one?

level: juniorimportance: must knowfreq 60%
basics
~20 s

A key type and a payload type vary independently, so each needs its own placeholder. A placeholder takes one type argument per use, so a single placeholder would force every route key and its payload to be the same type.

open as a page

A lost-property desk stores every item as one universal supertype and casts on collection — what does a type parameter buy instead?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A type parameter moves the wrong-kind failure from collection time to the deposit call, and from run time to compile time. Callers also get items back already typed, so no downcast on retrieval can fail.

open as a page

Why must a connection's outbox, send and receive share one declaration-level placeholder rather than each introducing its own?

level: middleimportance: must knowfreq 57%
basics
~20 s

Only a placeholder introduced on the declaration is one name that all members mean the same thing by. Give each operation its own and nothing ties them together: a value put in and a value taken out need never match, and the stored buffer agrees with neither.

open as a page

An unrestricted placeholder type in a payroll totalling routine — what may its body do with each element?

level: juniorimportance: must knowfreq 66%
basics
~20 s

Only what every type supports: hold it, pass it on, return it. With no limit written, the placeholder is implicitly pinned at the widest type available, so no pay-component operation such as reading an amount is callable on it.

open as a page

A board routine needs its departure placeholder both time-orderable and fixed-width renderable - why two requirements instead of one supertype?

level: middleimportance: must knowfreq 58%
basics
~20 s

Listing two requirements on one placeholder admits any type that already orders and already renders, unchanged. A combined supertype forces every candidate to be redeclared under it, which is impossible for types you do not own, and welds two unrelated capabilities together.

open as a page

In a tournament ladder, why limit the entrant placeholder in terms of itself rather than to a plain comparable supertype?

level: middleimportance: must knowfreq 58%
basics
~20 s

A self-referential limit types each entrant's comparison against its own type, so comparing two unrelated kinds of entrant fails to compile. A plain comparable supertype only promises comparison with some entrant, leaving the mismatch to surface at run time.

open as a page

Requiring an add-in to implement a published interface versus requiring only the operations you call — what does each demand of the add-in team?

level: middleimportance: must knowfreq 62%
basics
~20 s

Naming a supertype demands that the add-in team edit their type's declaration and take a build dependency on your published artifact. Requiring a shape demands only that the members exist, so a type written before your host can qualify unchanged.

open as a page

What decides whether a payroll routine's placeholder is pinned at or above a type rather than at or below it?

level: middleimportance: must knowfreq 54%
basics
~20 s

What the body does with the value. If it calls that type's own operations, pin the placeholder at or below the type; if it only hands values of that type in somewhere, pin it at or above.

open as a page

An array of premium seats is passed where an array of seats is expected, then a standard seat is stored - why is that unsafe?

level: juniorimportance: must knowfreq 62%
basics
~20 s

The array's real element type is still premium-only, so the store plants a value the original holder's type promises can never be there, and the next read of that slot returns something the reader believes is impossible.

open as a page

Reading a row source declaration, what makes its placeholder a producer rather than a consumer?

level: juniorimportance: must knowfreq 60%
basics
~20 s

A placeholder is a producer when every member that mentions it hands a value of it back: it appears only as output — a return type or a readable property — and never as a parameter the caller supplies.

open as a page

Electric vans are vehicles. Does it follow that a roster of electric vans is a roster of vehicles?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Not automatically. A subtype relation between two element types says nothing on its own about the containers over them; the container type decides. Three answers are possible - covariant, contravariant, invariant - and invariance is the usual default.

open as a page

A shared policy library can state a type's variance once on the declaration or let each caller narrow it - what does each buy?

level: middleimportance: must knowfreq 55%
basics
~20 s

Declaration-site states the direction once, so every use gets the subtyping free - but only for a type whose parameter sits in one direction. Use-site keeps the type invariant and lets each signature narrow its own view, repeatedly.

open as a page

In a language design where an array of a subtype is an array of its supertype, what must happen on every store?

level: middleimportance: must knowfreq 58%
basics
~20 s

Each store is tested at run time against the element type the array was actually created with, and a value that does not fit is rejected right there, at the write - not at the call that let the widened array through.

open as a page

Why does a language that discards type arguments reject a run-time test asking whether a value is a stack of text edits?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A run-time test can only read what the value still carries, and the discarded argument is not there. Every stack of edits shares one run-time shape, so the test cannot be decided, and the compiler rejects it instead of guessing.

open as a page

A settings loader is handed the expected type as an argument alongside the key — what does it do with that argument?

level: juniorimportance: must knowfreq 55%
basics
~20 s

The type argument is the evidence the run time no longer carries: the loader uses it to choose how to convert the stored text and to check the converted value before returning it, so a mismatch fails at the read.

open as a page

After compilation on a platform that discards type arguments, what does a stored container value still record about its argument?

level: juniorimportance: must knowfreq 65%
basics
~20 s

Nothing you can ask the value for. The argument is spent during compilation, and what runs is an ordinary container over the erased element shape. Only a declaration, never the object it points at, may keep a written description of it.

open as a page

Why would a platform add parameterized types by checking the arguments and then discarding them from the compiled artifact?

level: middleimportance: must knowfreq 58%
basics
~20 s

Discarding keeps the compiled shape identical to the pre-parameterized one: one body serves every instantiation, the existing run-time system needs no change, and code compiled before the feature can still call, and be called by, parameterized code.

open as a page

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

level: middleimportance: must knowfreq 55%
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.

open as a page

A decoder body is written once against a placeholder sample type: which two strategies can a toolchain use to make it run?

level: middleimportance: must knowfreq 58%
basics
~20 s

A toolchain can generate a separate copy of the body for each type argument, with every operation resolved to a direct call, or compile one shared copy that receives the type's operations as a passed-in table and calls them indirectly.

open as a page

An archiver's generic record writer also ships a hand-written body for one chosen type argument - what decides which body runs?

level: middleimportance: must knowfreq 58%
basics
~20 s

The most specific matching definition wins. Where the type argument becomes known, every candidate whose pattern that argument satisfies is gathered, and the narrowest is selected; the general body is the fallback for arguments nothing narrower claims.

open as a page

A tile renderer stores coordinate points in a generic container; why does each point cost an allocation and an extra memory hop?

level: middleimportance: must knowfreq 58%
basics
~20 s

A shared container body is compiled once against one uniform slot shape — a reference — so an unboxed point cannot sit in the buffer directly. Each point becomes a separate heap object and the slot holds that object's address.

open as a page

Compiling a separate body for each type argument makes calls faster - what does the build pay for that speed?

level: middleimportance: must knowfreq 52%
basics
~20 s

Per-argument body generation costs build time (a fresh compile per distinct argument), artifact size (every generated body ships), and instruction-cache pressure (more distinct code competing for the same cache). The gain is a direct, inlinable call with no run-time indirection.

open as a page

In your archiver, the hand-written body for one record type drifted from the general body - why does the bug appear only at some call sites?

level: seniorimportance: must knowfreq 48%
basics
~20 s

Because which body runs is decided by what each call site statically knew about the type, not by the value. A site that fixed the argument takes the drifted body; a site still holding it generically can keep running the general one.

open as a page

A routine takes one value of an unknown type and returns a value of that same type — what can its body return?

level: middleimportance: must knowfreq 50%
basics
~20 s

Only the value it was handed. A body that can neither inspect nor construct a value of an unknown type has no other value of that type in scope, so the one body that returns a result returns its argument.

open as a page

Why can a relay body that carries any caller-chosen payload type not branch on which type it was handed?

level: middleimportance: must knowfreq 55%
basics
~20 s

Because the signature promised the same behaviour for every type a caller may name, and behaviour that depends on the choice makes that promise false for the rest. An unconstrained placeholder also declares no capability, so there is usually nothing to branch on.

open as a page

In a relay that carries a payload of any type the caller names, who fixes that type, and when?

level: middleimportance: must knowfreq 62%
basics
~20 s

The caller fixes it, independently at every call site. A universally quantified signature promises the same behaviour for every type a caller may name, so the implementation is written once and has to hold for all of them.

open as a page

A validation helper must work for any result wrapper rather than any element type — what must its type parameter itself accept?

level: middleimportance: should knowfreq 46%
basics
~20 s

Its type parameter must itself take a type argument: it stands for a wrapper, not for a finished type. Such a parameter is higher-kinded, and its kind records how many arguments it still expects before it names a type.

open as a page

When a type system's placeholders cannot stand for a wrapper itself, what do teams write instead of one pipeline per wrapper?

level: seniorimportance: should knowfreq 40%
basics
~20 s

They normalise every stage result onto one chosen wrapper at the boundary, encode the wrapper as a marker type with lift and lower conversions, or generate the per-wrapper copies from a single source. Each trades the missing abstraction for a different cost.

open as a page