When a transform has no shipment line to produce for some order lines, what must its mapping stage's result still contain?
answer
- the stage cannot skip an input
- one entry per input, marker included
- the element type widens downstream
- the count moves only at the filter
- never a placeholder that looks like data
basics
~20 sOne entry per input, still — a mapping stage cannot skip. The transform has to put a placeholder in those positions, which widens the result's element type, and a separate filtering stage is what removes them afterwards.
solid answer
~50 sThe positional contract does not bend: the stage puts one entry in the result for every element it was given, so a transform with nothing to return must return something anyway. That something is a placeholder meaning "no shipment line here", and its presence widens the collection's element type from "shipment line" to "shipment line or nothing" for every stage downstream. Removing the placeholders needs a second stage — a filtering stage whose predicate rejects them — and the count drops only there. Two things are worth saying: the widened type should survive exactly one hop, because every stage in between has to decide what a placeholder means, and a placeholder that looks like ordinary data, such as a zero-quantity shipment line, is the worst choice because no predicate can tell it from a real one.
code
pseudocode · 9 lines// a mapping stage cannot skip: every order line yields one entry
marked = map(orderLines, function(line)
if line.hasShippableItems then
return toShipmentLine(line)
else
return NOTHING) // one placeholder, in that position
// the count drops only here
shipments = filter(marked, function(entry) return entry != NOTHING)go deeper
The thing to remember is that a mapping stage always returns as many entries as it was given. If the function has nothing to produce for an input, something still occupies that position.
Explain the consequence for the element type: the collection now holds "a value or nothing", and every function downstream has to handle both cases until a filtering stage removes the markers.
Show the discipline, not just the mechanism — keep the filtering stage adjacent so the widened type lasts one hop, and reject any marker that could be mistaken for real data, because nothing downstream will catch it.
The call you own is where absence is allowed to be represented at all. A convention that every pipeline handles absence the same way is worth more than any single pipeline's cleverness, because the failure mode is silent and shows up in whatever counts the results.
## The contract forces the placeholder A mapping stage is positional: for element *i* of the input it puts one entry at position *i* of the output. There is no branch in that contract for "the transform had nothing to say". So when a transform genuinely has no shipment line to produce — the order line has no shippable items, the address failed validation, the product was withdrawn — it still has to return a value, and the only honest value is one that means **absence**. The result of the stage is therefore not a collection of shipment lines. It is a collection of *slots*, each holding either a shipment line or a marker that there is none, and it has exactly as many entries as the input had. ## The element type widens That is the real cost, and it is the part candidates miss. Before the stage, the collection's element type was "order line". After it, the element type is "shipment line **or** nothing". Every stage that reads the collection from here on has to cope with both cases: - a following transform has to decide what to produce for a placeholder; - a following predicate has to decide whether a placeholder passes; - anything that reads a field off an entry has to establish first that there is an entry to read. The widened type is contagious in exactly the way an unhandled case is contagious, and the first stage whose function forgets the placeholder case treats a marker as if it were a real shipment line. ## The two-stage shape The standard arrangement is a mapping stage immediately followed by a filtering stage whose predicate rejects the placeholders: ``` marked = map(orderLines, toShipmentLineOrNothing) // n entries, some are NOTHING shipments = filter(marked, isPresent) // k entries, no NOTHING left ``` The count moves only at the second stage, which is exactly what the two contracts predict. The important discipline is **adjacency**: put the filtering stage right behind the mapping stage, so the widened type exists across a single hop and no other function ever has to know about placeholders. ## Why the filtering stage does not narrow the type After every placeholder has been rejected, the collection still *admits* one as far as its declared element type is concerned. That is not an oversight — it is the filtering contract. Filtering selects entries; it does not transform them, so the element type is unchanged by construction. What a predicate knows at run time is not a fact the collection's type can record. Narrowing back to "shipment line" takes another stage that actually produces a value of the narrower type. Expecting the filter to do it is the same mistake as expecting a filter to edit what it keeps. ## The alternatives, and what each one costs | choice | what it costs | |---|---| | a distinct marker meaning absence | one widened hop; every following function must handle it until the filter runs | | an ordinary-looking data value, such as a zero-quantity line | indistinguishable from real data; no predicate can reliably reject it, and it reaches reporting as a real shipment | | signalling an error from the transform | turns a per-element outcome into a pipeline-wide one: the traversal ends at the first such line and everything already produced is discarded | | making the transform return zero-or-more entries | a different stage shape entirely, with a different contract — not a plain mapping stage, and the count then moves at the mapping step | The second row is the trap worth naming in an interview. A placeholder that is valid-looking data is not a placeholder; it is a bug that has been given a plausible shape, and it survives every filter because there is nothing about it to reject. The third is the one a reviewer proposes when the absence feels exceptional. It is worth taking seriously only when a single bad element really does invalidate the whole batch. If the point of the pipeline is to ship what can be shipped, ending the traversal at the first unshippable line throws away the work done on the lines that were fine and hides how many of them there were. ## What a strong answer sounds like "The stage cannot drop, so the transform returns a marker and the element type widens to include it; I put the filtering stage immediately after so the widened type lasts one hop; and I never use a value that could be mistaken for a real shipment line, because then nothing downstream can tell the difference." That answer shows the shape contract, the type consequence and the failure mode in three sentences, which is what the question is looking for.
- Why is it a problem to let the placeholder-carrying collection travel more than one stage?Because every stage in between is written against the widened element type: each transform and each predicate has to decide what a placeholder means, and the first one that forgets treats it as a real shipment line. Keeping the filtering stage adjacent confines the widened type to a single hop.
- A reviewer suggests having the transform signal an error for those lines instead. What does that change?It converts a per-element outcome into a pipeline-wide one. The first unshippable line ends the traversal, so the entries already produced are discarded and the lines not yet reached are never examined. Returning a value keeps the decision per element, which is what the pipeline was for.
- Is a zero-quantity shipment line an acceptable placeholder?No — it is the worst option. A placeholder has to be distinguishable, and a valid-looking record is not: no predicate can separate it from a genuine zero-quantity shipment, so it survives the filtering stage and arrives wherever the results are counted or billed as if it were real.
saying these in an interview costs you the question
- Says a mapping stage can simply skip the inputs it has no value for.
- Uses a legitimate-looking data value as the marker for absence.
- Lets the placeholder-carrying collection flow through several later stages.
- Assumes the filtering stage also narrows the declared element type.
- Turns a per-element absence into an error that ends the whole traversal.