The convenience of writing `?` means nobody will bother wrapping errors anymore. Is what I understand of this extremely dubious argument.
Since you could just design your `?` to encourage wrapping instead.
The convenience of writing `?` means nobody will bother wrapping errors anymore. Is what I understand of this extremely dubious argument.
Since you could just design your `?` to encourage wrapping instead.
Which is exactly what Rust does -- if the error returned by the function does not match the error type of `?` expression, but the error can be converted using the `From` trait, then the conversion is automatically performed. You can write out the conversion implementation manually, or derive it with a crate like thiserror:
#[derive(Error)]
enum MyError {
#[error("Failed to read file")
IoError(#[from] std::io::Error)
// ...
}
fn foo() -> Result<(), MyError> {
let data = std::fs::read("/some/file")?;
// ...
}
You can also use helper methods on Result (like `map_err`) for inserting explicit conversions between error types: fn foo() -> Result<(), MyError> {
let data = std::fs::read("/some/file").map_err(MyError::IoError)?;
// ...
}2. Idiomatic go type erases errors, so you're converting from `error` to `error`, hence type-directed conversions are not even remotely an option.
.map_err(|e| format!("Failed to read file: {e}")?;
But the "idiomatic Go" way of doing things sounds a lot closer to anyhow in Rust, which provides convenience utilities for dealing with type-erased errors: use anyhow::{Result, Context};
fn foo() -> Result<()> {
let data = std::fs::read("/some/file").context("Failed to read file")?;
// ...
} fn foo() -> Result<()> {
let data = std::fs::read("/some/file")?;
// ...
}
whereas the current morass of Go's error handling means adding wrapping is not much more of a hassle.But of course even if you accept that assertion you can just design your version of `?` such that wrapping is easier / not wrapping is harder (as it's still something you want) e.g. make it `?"value"` and `?nil` instead of `?`, or something.
In practice, the error type will be defined quite close to where the conversion is applied, so the static nature of it doesn’t feel too big.
A thread from two days ago bemoans this point: