While coding in Rust, I don't have to keep a lot of things in my head thanks to the strong guarantees provided by the compiler. In contrast, while coding in Python, I have to remember what are the exact names of the attributes of duck
that def use_duck(duck)
uses. Not to mention whether use_duck
is allowed to modify duck
or am I allowed to use duck
again after the function exits.
Most of the information that we need to correctly use a function is provided in the type signature of that function.
Although, there is one more thing that is desirable in the type signature: The error conditions expected by the function.
This is inspired from this post: What Conditions (Exceptions) are Really About « Dan Weinreb’s Weblog
For example:
fn open_file(path: &str, mode: Mode) -> File
errors [MalformedPath, FileNotFound, IOError] {
// ....
}
fn do_something_with_file()
errors [FailedToOpenFile{msg: String}] {
let file = open_file("/foo/bar.txt", Mode::ReadOnly)
.map_err(|err| match err {
MalformedPath => FailedToOpenFile{
msg: String::from("Please make sure the path is well fromed")
},
_ => FailedToOpenFile{
msg: String::from("Unexpected error while trying to open file")
}
})?;
// do stuff with file
}
Compared to checked exceptions in Java, adding a new error condition to open_file
, say PermissionDenied
doesn't require us to modify do_something_with_file()
because we use a catch all pattern while matching over errors.
I am not sure how easy this is to implement.
One simple (from the user's perspective) way to do this is by desugaring:
fn foo(..) -> T
errors[ <<errors>> ] {..}
// this desugars to
enum _FooError {
<<errors>>
}
fn foo(..) -> Result<T, _FooError> {..}
But that leaves the question of how to refer to the generated enum
s while pattern matching over it.
It would be really nice and ergonomic if the compiler is able to infer this from the types.
Is it possible to implement something similar to this?
Is it possible in today's Rust to approximate this?
Do you have any other idea to make error conditions more visible?