Files
learn-rust/learning-records/0005-from-written-but-not-reached-for.md
T

39 lines
2.4 KiB
Markdown

# A trait impl can be written correctly and still not be reached for
The 0006 drill landed 24/24 with the shipped spec unedited: seven `TaskError` variants, correct `Display`
sentences, `source()` returning the wrapped `ParseIntError` for exactly one variant, and
`impl From<ParseIntError> for TaskError`. Every trait obligation was produced from the signature up.
And the `From` impl was never called. `command.rs` still converted by hand, twice:
```rust
let id: u32 = match id.parse() { Ok(n) => n, Err(e) => return Err(TaskError::BadId(e)) };
```
That is `From::from` typed out longhand. The tests pass either way, so nothing in the feedback loop objected.
## Evidence
Read against the real crate, plus `cargo clippy`: 24 green, `tests/errors.rs` byte-identical to
`lessons/0006-errors-spec.rs`, two duplicated `match id.parse()` blocks in `command.rs`, and the same
`match … Ok(_) => ()` in `main.rs` that LR-0004 flagged after 0005 (clippy's `single_match`).
The follow-up questions were the more useful signal. All three were about the *mechanism*, not the syntax:
can two `From` impls exist for one type, where does the wrapped message go, does a developer walk `source()`
by hand every time. The syntax was owned; the model of what the syntax buys was not.
## Implications
- **A drill step needs a check that fails when the point is missed.** "Both `match` blocks collapse to
`id.parse()?`" was written in the 0006 prose and had no check beside it, so it did not happen — the same
failure mode as the stderr/exit-1 contract in LR-0004, now seen three times. 0007 gives it a grep check
(`grep -c "match id.parse" src/command.rs` → `0`) as step 0.
- **Force the impl, do not suggest it.** In 0007 the second conversion (`From<io::Error>`) cannot be hand-rolled
around without the compiler complaining, because `?` on `fs::write` is the only reasonable shape. `E0277`
does the teaching that prose could not.
- **Recall of "why" still lags production.** Same pattern as the 0005 quiz (Enums 0/1 while writing three enums).
The fix that works is showing real compiler output for the failure mode, not asserting the rule — so 0007
ships `E0119`, `E0277`, `E0046`, and `E0369`, each captured by running it.
- The user asks precise mechanism questions when given room to. Budget for them: leaving the ladder of
`?` → `From` → `source()` → `anyhow` explicit in the lesson costs less than answering it four times after.