Otherwise, it seems to me that what you are asking is "Why didn't the Rust developers ship a 20 year old language on day 1?".
Otherwise, it seems to me that what you are asking is "Why didn't the Rust developers ship a 20 year old language on day 1?".
What do you mean by "a lot of churn"? The only significant thing I can think of is that the try! macro turned into the ? operator.
They added `expr?` as sugar for `try!(expr)`, but that's about it.
fn read_i32_from_file(path: &str) -> Result<i32, ???> {
let bytes = std::fs::read(path)?; //may return std::io::Error
let text = std::str::from_utf8(&bytes)?; //may return std::str::Utf8Error
return text.parse(); //may return std::num::ParseIntError
}
What do you enter as error type in the type signature? In most cases, it would be sufficient to use Box<dyn Error>, but that requires boxing and thus an allocation, which is something that many libraries want to avoid to be useful for no_std or resource-constrained usecases. An answer to this could be to define enum ReadI32FromFileError {
Read(std::io::Error),
Decode(std::str::Utf8Error),
Parse(std::num::ParseIntError),
}
and then you have to provide a bunch of trait implementations for that new error type (esp. to cast the constituent error types into this type). That's a whole lot of boilerplate, and most of the error handling crates are about cutting down on this boilerplate.Another problem with the std::error::Error trait is that until 1.30 it didn't provide a nice way to traverse error chains. Even now, the new cause() method may not be supported by all the error types from all the libraries you care about.
Okay, so you are in a resource-constrained environment. What would you do in C or C++? You can't do exceptions in C++ here, because there's allocation and other ugliness for embedded or whatever. You can always have your rust code return an int, like we do in C if the boilerplate is too much for you.
On the other end, you have Kotlin and Swift Results. Kotlin type-erase the error completely. And I'm pretty sure Kotlin's Result allocates on failure. I'm not sure about Swift. But are you running Swift, with its heap allocated `class` and reference counting on embedded? You're surely not running Kotlin.
Sure, if you have complete control over all the source code. I'd like to use my standard set of libraries regardless of whether the code in question is resource-constrained.
(Side-note: I specifically said "resource-constrained" instead of "embedded" because you can have resource-constrained code in an otherwise not-constrained application, e.g. in tight computation loops where you want to avoid heap usage to benefit cache locality).
> a lot of this churn could have happened "in userspace": different approaches to async or error handling would be library changes rather than language changes.
is exactly what has been happening, for error handling.
Not sure I understand... All these other recent languages you mentioned were released after Rust, so Rust couldn’t have benefited from them on day 1. The opposite happened: most of these other languages took design lessons from the languages that preceded them, including Rust.