In a relay that carries a payload of any type the caller names, who fixes that type, and when?
answer
- read the quantifier in front
- one promise, many callers
- the choice is made outside
- fixed per call site, not per program
- written once, correct for every choice
basics
~20 sThe 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.
solid answer
~40 sRead the signature with its quantifier out loud: *for every type the caller may choose*, this relay accepts a payload of that type and hands back one of the same type. The choosing happens on the caller's side, at the call site, and one call site's choice binds nothing for any other — the same relay can carry one payload type here and a different one three lines later. The implementation never gets a vote: it is written once against the placeholder and must be correct for every choice, including types that did not exist when it was written. That is what turns the parameter into a promise rather than a hint — the caller supplies the type argument, the implementation supplies the guarantee.
code
pseudocode · 8 lines// the signature quantifies over every type a caller may name
function relay<T>(payload: T) returns T
// each call site fixes the payload type on its own
ticketBack = relay<Ticket>(ticket) // here the choice is Ticket
envelopeBack = relay<Envelope>(envelope) // and here, independently, Envelope
// one body served both; neither call constrained the othergo deeper
Recall the plain reading: a parameterized signature says "for any type you name", and you, the caller, are the one naming it at the point of the call.
Explain that the choice is made per call site and binds nothing elsewhere, and that the body is written once and must be correct for every choice, including types written after it.
Show what this buys in a real codebase: the relay needs no change when a new payload type appears, and reading one call site tells you what every other call site does.
Frame it as the contract a platform team publishes: a quantified signature is a promise to callers you will never meet, and it costs you the freedom to ever special-case one of them.
## The quantifier in front of the signature A parameterized signature is not a template with a hole punched in it; it is a claim with a quantifier in front. Spelled out in words, a relay declared as `relay<T>(payload: T) returns T` says: **for every type `T` a caller may name, this relay accepts a `T` and returns a `T`.** The phrase *for every* is the whole content of the declaration, and it is where the name **universal quantification** comes from. Everything else in this topic follows from taking that phrase literally. The practical consequence is that the signature is not describing one relay that happens to work for one type. It is describing a family of relays — one for each type a caller could ever name — all of which are guaranteed by a single body. ## Who does the choosing - **The caller does**, and it does so at each call site where the relay is used. - The choice is fixed **per use**, not per relay, per module or per process. One call may carry one payload type and the next call a completely different one. - One call site's choice places **no restriction** on any other call site's choice. There is no first-come-first-served instantiation. - The choice may be written out explicitly or reconstructed from the call — from the arguments passed, from the type the result is used as, or from the surrounding context. Where it is reconstructed, the choice still **originates at the call site**; the shorthand only spares the caller from spelling it out. - The set of choices includes types that **did not exist** when the relay's body was written, and types written by teams the relay's author will never meet. ## What the implementation gets in exchange The implementation receives an obligation, not a choice: 1. It is written **once**, against the placeholder, with no knowledge of any particular payload type. 2. It must be correct for **every** instantiation, including the ones made years later. 3. It may not make its behaviour depend on **which** type was chosen, because the promise was made uniformly over all of them. That third point is the price of the first. A body that could consult the caller's choice would be making a different, weaker claim: *for every type, this relay does something, and what it does is up to it*. Nobody would rely on that. ## Read it in the right direction This material is easy to state backwards, and a backwards statement is still grammatical, so it survives review. The table below pins the direction. | Read it this way | Not this way | |---|---| | The caller names the type; the body must handle every name | The body picks a type and the caller adapts | | The choice is fixed at each call site | The choice is fixed once for the whole program | | The promise ranges over types not yet written | The promise covers only types known at authoring time | | One body, many instantiations | One instantiation, many bodies | | The signature is a guarantee to the caller | The signature is a hint the body may ignore | ## What the caller actually buys Because the caller named the type, the caller keeps it: - The value handed back is of the **type the caller named**, so nothing has to be recovered or re-established on the way out. - The behaviour is **uniform across call sites**, which is why reading one call site tells you what every other one does. - A new payload type needs **no change to the relay** — the promise already covered it. - The relay's author can change the body freely as long as the promise still holds for every choice, because no caller was ever told anything else. ## Where platforms differ, and why it does not change the promise Platforms differ in what they do with the caller's choice after checking it: some compile a single shared body that every instantiation runs, others generate a separate body per type argument. That difference is a compilation strategy with real costs attached, and it is a subject of its own. It changes nothing about who chose the type or when — in both arrangements the caller made the choice at the call site and the author wrote one piece of source that had to be right for all of them.
- If a caller never writes the type argument out, has the choice stopped being the caller's?No. Where the argument is left out it is reconstructed from the call — the values passed, the type the result is used as, or the surrounding context. The choice still originates at the call site; the shorthand only saves the caller from spelling it out, and where the context is too thin to reconstruct it, the platform asks for it back.
- Can two call sites that name the same payload type still see different behaviour from the relay?Not from the type argument alone. The body is one body quantified over every choice, so two call sites naming the same type see the same behaviour for the same inputs. Any difference has to come from something else the caller passed in — a value, a flag, an operation — never from which type was named.
- Does a universally quantified signature promise anything about types that did not exist when it was written?Yes, and that is the point of the quantifier. It ranges over every type a caller may name, so a type introduced later is covered by the original promise without the relay being touched. That is only sustainable because the body cannot depend on which type it was handed.
saying these in an interview costs you the question
- Thinks the implementation decides which payload type shows up
- Says the type argument is fixed once for the whole program
- Believes one call site's choice constrains later call sites
- Treats the placeholder as a stand-in for one common supertype
- Assumes the body may consult the caller's choice when convenient
- Thinks the promise covers only types that existed at authoring time