The renderer calls every formatter with two arguments, the value and its row — what does supplying a one-parameter function violate?
answer
- the call site fixes the count
- arity, not just the types
- ignoring an argument is a body detail
- declare both parameters, use one
- wrap it in a two-argument adapter
basics
~20 sArity is part of a function's type, not a detail of the body. A one-parameter function therefore has a different type from a two-argument slot, and needs an adapter that takes both arguments and forwards one.
solid answer
~40 sIt violates **arity**, which is part of the function's type and not an implementation detail. The slot's call site is fixed — two arguments go out on every call — so a function declaring one parameter is a different type, not a close enough fit the renderer can smooth over. The confusion usually comes from mixing two different things: *needing* an argument and *declaring* one. A formatter that has no use for the row still has to declare the parameter and ignore it; ignoring is a property of the body, which the type cannot see. The portable fix is an adapter — a two-parameter function whose body calls the one-parameter formatter with the first argument.
code
pseudocode · 13 lines// the renderer's call site, fixed:
// formatter(value, row)
function shortName(value) // one parameter: a different type
return firstWord(value)
end
// adapt it to the slot's arity
function shortNameCell(value, row)
return shortName(value) // the row is dropped here, once, visibly
end
renderer.setFormatter(column, shortNameCell)go deeper
Count the parameters on both sides before anything else. A function taking one argument is a different type from one taking two, even when the value types agree.
Separate the two layers: the type fixes how many arguments arrive, the body decides whether they are read. Then show the adapter that bridges them.
Anticipate the run-time version of this. Where a mismatch is not reported at the boundary, say what the first symptom looks like and where you would put the adapter.
Weigh the alternative to adapting: a hook that passes a single structured argument moves later additions out of the arity, at the cost of an extra indirection on every implementation.
The renderer's hook has grown: every formatter is now called with two arguments, the cell value and the row it came from. A column wants to supply a formatter that only ever looked at the value. The question is what exactly stands in the way, and the answer is one word with consequences. ## Arity belongs to the type A function type is arity plus the type in each parameter position plus the result type. Change the arity and you have a different type — not a variant, not a compatible subset, a different type. That is why the mismatch is reported before any parameter type is even compared, and why no amount of agreement on the value type or the result type rescues it. It helps to name the thing the arity describes: it is a property of **the call the caller will make**, not of the work the callee wants to do. The renderer has committed to pushing out two arguments per call. A value that cannot receive two arguments cannot be on the other end of that call. ## Needing an argument is not declaring one The usual objection is that the second argument is unused, so it cannot matter. That confuses two layers: - **The body** decides whether an argument is read. A formatter may declare the row and never touch it; nothing in the type notices. - **The type** decides how many arguments arrive. That is fixed at the declaration and checked before the body runs. So "I do not need the row" is expressible, and the way to express it is to declare both parameters and use one. What is not expressible is a function that declines to receive an argument the caller will send. A related move that looks like a solution and is not: giving the second parameter a default value. A defaulted parameter is still a declared parameter — the function's arity is two. The default changes which *callers* may omit an argument, and the renderer never omits one, so the default is never used. It is not wrong, it just buys nothing here. ## Adapting a one-parameter formatter 1. **Write a function of the slot's arity.** Two parameters, named for what arrives: the value and the row. 2. **Forward what the original needs.** Its body calls the one-parameter formatter with the first argument. 3. **Register the adapter, not the original.** The discarding of the row now happens in one visible place, written once, rather than being assumed by every call site. The cost is one indirection and one more name. The benefit is that a reader can see exactly where the row is dropped, which is the kind of thing that otherwise gets rediscovered during an incident. ## Where language families part company How strictly the mismatch is enforced differs. Some languages treat arity as part of the checked type and refuse the value outright — the safest outcome, because the problem is found where it was written. Some calling conventions pass arguments in a way that lets a callee simply not see the surplus, so a one-parameter function runs happily and silently ignores the row; the code works until someone assumes the declaration means the row is unavailable. And some check nothing until the call happens, turning the mismatch into a run-time failure on the first rendered row. The rule about what a function type *is* does not change across the three; only who reports the violation, and when. ## The confusions this question separates | Claim | Verdict | |---|---| | "An unused argument cannot affect the result, so the shapes agree." | Wrong layer — the type is decided before the body runs. | | "The renderer should notice the shorter parameter list and adapt." | The caller's arity is the contract, not a hint to be negotiated. | | "Widening the result type compensates for the missing parameter." | The positions are independent; nothing about the result supplies an argument. | | "A default on the second parameter makes it optional for the renderer." | Arity is still two; the renderer passes both, so the default never fires. | ## Why an interviewer asks it It is a cheap way to find out whether a candidate thinks of a function's shape as a type or as a suggestion. The candidate who says "wrap it" has the right model and will type callbacks correctly under pressure; the candidate who says "the extra argument will just be ignored" has been relying on a calling convention they cannot name and will be surprised the first time it is not there.
- What does the adapter look like, and what does it cost?A two-parameter function whose body calls the original with the first argument and never touches the second. It costs one indirection and one name. What it buys is that the row being discarded is visible at the boundary, written once, instead of being assumed silently at every call.
- Why not give the second parameter a default value instead?A default still means the function declares two parameters, so the arity is unchanged; a default governs which callers may omit an argument. Since the renderer always passes both, the default never fires. The honest form is to declare both parameters and ignore one.
saying these in an interview costs you the question
- Says an unused second argument cannot matter, so the function fits.
- Calls arity a calling convention rather than part of the type.
- Expects the renderer to notice the shorter parameter list and adapt.
- Confuses the arity mismatch with a mismatch of parameter types.
- Thinks a wider result type compensates for a missing parameter.