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

2.4 KiB

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:

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.