How does the question mark operator use From to unify error types?
This tests Rust error conversion mechanics. You define a unified enum error and implement From for each source error so ? automatically converts via From::from. A red flag is suggesting manual match or map_err on every call instead of trait-based conversion.
WHAT THIS TESTS: This question probes whether you understand the desugaring of the question mark operator and how Rusts type system enables ergonomic error propagation. Specifically it checks if you know that the operator does not require homogeneous error types across a call graph, and that the From trait is the bridge that makes automatic conversion possible. Interviewers care about this because it separates candidates who write boilerplate-heavy error handling from those who leverage the type system.
A GOOD ANSWER COVERS: A good answer hits four things in order. First, explain that the function signature uses a single unified error type such as Result<T, MyError>. Second, describe that each distinct underlying error gets its own variant inside a custom MyError enum, for example IoError(std::io::Error) or ParseError(std::num::ParseIntError). Third, state that you implement From<UnderlyingError> for MyError for each source error type, and that this implementation wraps the source error into the appropriate variant. Fourth, clarify that when the compiler sees the question mark operator, it desugars the expression into a match that returns Err(From::from(err)) on the error arm, which means the conversion happens automatically at every call site without manual mapping.
COMMON WRONG ANSWERS: A common wrong answer is saying you must use map_err on every Result to transform the error before applying the question mark operator. Another red flag is claiming that the operator only works when every function called returns exactly the same error type as the parent function. Some candidates also suggest using Box<dyn std::error::Error> as the only way to unify errors, which works but misses the point of the question about explicit typed conversions via From. Finally, confusing From with TryFrom is a signal that the candidate does not understand infallible versus fallible conversions.
LIKELY FOLLOW-UPS: An interviewer might ask how this interacts with the Into trait, since implementing From automatically yields a blanket Into implementation. They might also ask what happens if you forget one From implementation, in which case the compiler will complain that the error type inside the operator expression does not implement From for your unified error. Another follow-up is how to preserve backtraces or source errors, which leads to discussing the source method on the Error trait or using crates like thiserror. They could also ask about performance, where the answer is that the conversion is usually a zero-cost enum wrapping.
ONE CONCRETE EXAMPLE: Imagine a CLI tool that reads a file and parses a number. The file open returns std::io::Error and parse returns std::num::ParseIntError. You define an enum AppError with variants Io(std::io::Error) and Parse(std::num::ParseIntError). You then write impl From<std::io::Error> for AppError that maps the io error into AppError::Io, and impl From<std::num::ParseIntError> for AppError that maps into AppError::Parse. Inside your main function returning Result<(), AppError>, you call std::fs::read_to_string("data.txt") followed by the question mark operator and then content.trim().parse::<i32>() followed by the question mark operator. The first operator converts the io error into AppError::Io automatically, and the second operator converts the parse error into AppError::Parse automatically, letting both propagate with no manual mapping.
Read the original → doc.rust-lang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.