skip to content

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%

answer

  1. the argument is gone; the caller is not
  2. evidence passed as an ordinary value
  3. used twice: choose, then check
  4. conversion selected from what it names
  5. narrowed before it is handed back

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.

solid answer

~50 s

A generic read body knows only a placeholder, and on a platform that discards type arguments it cannot ask what that placeholder stands for. So the caller hands the type over as an ordinary run-time value — a **class token** — and the loader uses it twice. First it selects the conversion: stored characters become a whole number, a flag or a duration according to what the token names, because the text alone cannot say which. Second it narrows the converted value against that same token before returning it, so a store holding the wrong text fails at the read, with the key still in hand. The call site pays nothing for the extra parameter: the result type of the call is tied to the type the token stands for, so the caller gets a typed value back and writes no cast.

code

pseudocode · 10 lines
pseudocode
function read(key, typeToken):
    text = store.lookup(key)
    if text is absent:
        return nothing
    converter = converters.forType(typeToken)   # the token picks the parser
    value = converter.parse(text)
    return typeToken.checkedNarrow(value)       # and checks the result here

port    = read("server.port", tokenFor(WholeNumber))
timeout = read("server.timeout", tokenFor(Duration))

go deeper

for a junior

Recall the shape of the call: you pass the key and the type you expect, and you get that type back without casting. The extra argument exists because the routine cannot see the type on its own.

for a middle

Explain both jobs the evidence does — selecting the conversion and checking the produced value — and say why the check belongs inside the read rather than at each call site.

for a senior

Talk about failure placement: configuration read once at startup, checked there, fails with the key in hand; unchecked, it fails later in unrelated code. Show where you put the single unchecked step and how you keep it to one.

for a principal

The tradeoff to own is boundary design: every typed read that takes evidence is an extra parameter on every call, and the alternative is a loosely typed map plus scattered casting. Decide once, for the whole codebase, and make the strict form the easy one.

## The gap the argument fills A typed read is declared against a placeholder: *give me the value stored under this key, as the type the caller asked for*. On a platform that **discards type arguments once the call has been checked**, the body of that read is never told the answer. The argument did its work in the compiler — accept or reject the call — and then it was dropped. What actually runs is one routine holding a key and a placeholder that stands for nothing it can inspect. That would be harmless if the body only moved values from one place to another. It does not. A settings store holds **text**: a port is characters, a flag is characters, a timeout is characters. Turning characters into a value requires knowing the target type, and the body is precisely the place that no longer knows it. The working answer is not to recover the type but to **be given it**. The caller passes the type as a value — a **class token**, an object that exists while the program runs and stands for exactly one type — alongside the key. The token is a *witness*: evidence, supplied at run time, for something the compiler knew and the run time forgot. ## The two jobs the token does 1. **It selects the conversion.** The loader asks the token what type it stands for, or looks a converter up in a table keyed by that type. The token is what picks *parse as a whole number* over *parse as a duration*. Without it the loader would have to guess from the characters, which is not typing: `10` is a count, a duration and a name, and nothing in the text prefers one. 2. **It checks the result.** Having produced a value, the loader narrows that value against the token before returning it. That is a real run-time check, and it is the whole difference between a signature that *promises* the caller a type and a routine that *verified* one. A weak version of the same API asks for the type only so the compiler can type the call, converts blindly, and hands the result back through an unchecked step. It compiles identically to the good version and fails much later. ## Why the caller still writes no cast The signature ties the token parameter and the result together: the token is declared as evidence *for the placeholder the call returns*. So the type the caller writes at the call site is the type the call has, and the caller neither casts nor tests. The unchecked work has been pushed into exactly one place — the loader — where it is done once, against real evidence, and can be reviewed. | Question about the read | Placeholder alone | Placeholder plus token | |---|---|---| | Can the body choose a conversion? | No — nothing names the target type | Yes — the token names it | | Can the body verify what it produced? | No — it can only assert | Yes — it narrows against the token | | Does the caller write a cast? | No, but the typing is a promise nobody checked | No, and the promise was checked at the read | | Where does a bad value surface? | At some later use, far from the store | At the read, with the key still in hand | ## Where a bad value surfaces This is the payoff worth saying out loud in an interview. Configuration is read at startup and used everywhere afterwards. If the check happens at the read, the failure names the key and the file; if the check never happens, the failure is a narrowing error deep inside unrelated code, hours of debugging away from the misspelled line that caused it. Handing over evidence is what buys the early failure. ## What the token is not - **Not a restoration of the argument.** The placeholder is still a placeholder; the body is still a body written against a name. The token is evidence about one type, held in one variable, used where the code deliberately reaches for it. - **Not a construction path.** Naming a type does not always let you build one — types whose construction needs arguments or is not publicly reachable need different evidence. - **Not a shape.** A flat token names one type. It cannot say *list of pairs of text and number*; the nesting has nowhere to live in a single name. ## Discipline at the boundary - Convert and check in **one** place, so there is one unchecked step in the system rather than one per call site. - Take the token as a parameter of the read itself, not as loader-wide state, so two reads of different types cannot interfere. - Tie the token's type to the placeholder in the signature; an untied pair is two statements of one fact that can drift apart. - Call the conversion only when there is text to convert, and treat an absent key as its own outcome rather than as a conversion failure.

  • If the loader skipped the narrowing step and just returned the converted value, would anything fail earlier or later?
    Nothing fails earlier; the failure moves. Without the narrow, the loader hands the value back through an unchecked step and the call site believes it. The mismatch then surfaces at the first operation that really needs the declared type, in unrelated code, with no key and no file name attached to it.
  • Why not let the loader guess the type from the stored text instead of taking a token?
    Because the text under-determines the type: the same characters read as a count, a duration, a version or a name, and an empty value reads as absent or as an empty string. Guessing makes the result depend on data rather than on what the caller declared, so the same file silently produces different types on different days.

A sample arrives at a lab with the assay written on the tube. The technician cannot infer from the liquid which test was wanted; the label is what selects the procedure and what the result is checked against.

saying these in an interview costs you the question

  • Claims the body can read the placeholder's type directly at run time
  • Thinks passing a token restores the argument for every operation
  • Says the converted value needs no check because the signature promises it
  • Cannot say where a wrong stored value actually fails
  • Treats the token as compile-time-only, like the argument it replaces