A processor meets a marked declaration it cannot handle: why report a positioned diagnostic instead of throwing?
answer
- anchor the message
- severity, message, position
- collect, do not abort
- throwing reads as a tool crash
- validate before you emit
basics
~20 sA positioned diagnostic lands on the author's own declaration and joins the build's other errors, so every problem in the round is reported at once. A thrown failure escapes as a tool crash, with no source line.
solid answer
~40 sThe build gives a processor a reporting channel: a severity, a message and the declaration to anchor it to. Using it produces an error that looks like every other compile error — file, line, message — pointing at the marker the author actually wrote. Throwing instead escapes into the build as a tool failure: the build reports that the processor blew up, usually with a stack trace through the tool's internals and no indication of which declaration caused it, and it abandons the round so the other marked declarations with the same mistake are never examined. Reporting also preserves the distinction between severities: an error fails the build after the round finishes, while a warning lets generation continue. Throwing collapses every condition into one outcome.
go deeper
Recall that a good tool tells you which line of your code is wrong. A message with a stack trace through the tool and no file or line is a sign the tool skipped the channel built for this.
Explain the channel's three parts — severity, message, anchoring declaration — and what throwing loses: the source position, the rest of the round's errors, and a clean build outcome.
Show the operating consequence: batch every failure in one build, validate before emitting so errors land on hand-written source, and pick severities so nothing surprising stops a shared build.
Set the reporting contract for tools every team's build depends on: what is an error versus a warning, where messages must anchor, and how a team opts out of a tool whose diagnostics they cannot act on.
## What the reporting channel carries A processing model hands each processor a way to say something to the build. Three things go into a report: - a **severity** — error, warning, or an informational note; - a **message** in the author's vocabulary, not the tool's; - an **anchor**: the declaration, member or marker value the message is about, which the build turns into a file and a line. That anchor is the whole point. The author did not write the processor; they wrote a marker on a declaration. An error that lands on that declaration is actionable. An error that lands nowhere is a bug report about somebody else's tool. ## What throwing actually produces When a processor throws instead: 1. The exception escapes into the build, which reports it as a failure of the tool rather than a problem in the code being compiled. 2. The message is the tool's internal wording, and the trace goes through the tool's internals — none of which names the declaration that triggered it. 3. The round is abandoned, so the remaining marked declarations are never examined. If twenty types carry the same mistake, the author fixes one, rebuilds, and meets the next. 4. Files already emitted in that round may be left behind, and the build's next attempt has to reconcile them. The last two are why the difference matters in practice rather than in principle: the reporting channel turns a twenty-build fix-one-at-a-time slog into a single build that lists all twenty. ## Severity is a real choice | severity | what it means | when to use it | |---|---|---| | error | the build fails after the round completes | the generated result would not be valid, or the request cannot be honoured | | warning | generation proceeds, the author is told | the marker is redundant, or a default was assumed for something ambiguous | | note | informational only | progress or summary output, usually off by default | Two mistakes recur. Using a warning where the outcome is unusable code moves the failure to a later, more confusing place — the author sees a compile error inside a generated file rather than a message on their own declaration. Using an error for something merely surprising makes the tool unadoptable, because any marked declaration that is slightly unusual stops the whole build. ## Errors do not stop the round A subtlety worth stating: reporting an error does not immediately abort processing. The processor is expected to skip the declaration it could not handle and carry on with the rest, reporting each failure as it goes. The build collects everything reported in the round and fails **after** it. That is how the author gets all the errors at once, and it is why an error report is usually followed by `continue` rather than by a return. The complement holds too: a processor that reports nothing and simply skips is the worst of both, because the author sees neither generated code nor an explanation. ## The interaction with rounds Because generated output re-enters as input, a diagnostic in a later round points at a **generated** file. That is honest but unhelpful, since nobody wrote that file. A processor that validates early — checking the shape of the marked declaration before emitting anything against it — keeps its diagnostics anchored on hand-written source, where the fix belongs. Validation deferred until the generated file fails to compile produces exactly the error the author cannot act on. There is a matching rule for the end of the loop: a condition that can only be known once everything has been generated, such as "two marked declarations claimed the same generated name", has to be reported in the last round the processor is called in, because there is no later one. ## How to answer this in an interview Name the channel and its three parts, name what throwing loses — the anchor, the batch, and the rest of the round — and give one example of choosing severity honestly. The register here is diagnostic: the interviewer is checking whether you have been on the receiving end of a tool that failed with a stack trace and no line number, and whether you know that the mechanism offered a better option the author of that tool did not take.
- Should reporting an error stop the processor for the rest of the round?No. Skip the declaration you cannot handle and carry on reporting the others; the build collects the round's diagnostics and fails afterwards. Aborting on the first error forces the author into a fix-one-rebuild loop, which is exactly the experience throwing produces.
- Why is a diagnostic reported from a later round often unhelpful?Because later rounds process generated files, so the message anchors to a file nobody wrote. Validating the marked declaration before emitting anything against it keeps the error on hand-written source, where the fix actually is.
- When is a warning the wrong severity?When the condition means the generated code will not be valid. The build then proceeds and fails inside a generated file, with a message about code the author never wrote, instead of on the declaration they did write. Warnings are for redundancy and assumed defaults, not for unusable output.
saying these in an interview costs you the question
- Throws from the processor and expects a readable build error
- Thinks reporting an error must abort the round immediately
- Reports a problem with no declaration attached to it
- Uses a warning for a condition that makes generated code invalid
- Assumes failing the whole build is the only signal available
- Defers validation until the generated file fails to compile