Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It took 20 years to get OCaml where it is. You can always wait another 20 years, and only start using Rust then.

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?".



The way I see it, Rust's day-1 error handling story was significantly worse than that of most recent languages (e.g. Swift, Typescript, Kotlin, Dart, just going down Wikipedia's list of significant languages). And it's not clear what Rust gains from that - after a lot of a churn it's not come up with a significantly better error-handling paradigm than what was already out there. So it just feels like a waste.


> Rust's day-1 error handling story was significantly worse than that of most recent languages (e.g. Swift, Typescript, Kotlin, Dart, just going down Wikipedia's list of significant languages). And it's not clear what Rust gains from that...

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.


I'd say the same thing for the equivalent list of pre-Rust languages (with the exception of Go): Clojure, F#, Scala, D, C#.


Rust 1.0 error story hasn't changed much?

They added `expr?` as sugar for `try!(expr)`, but that's about it.


The big problem is that there isn't a single error type that every function can return. Take this example:

  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.


> 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.

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.


> You can always have your rust code return an int, like we do in C if the boilerplate is too much for you.

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).


It's true that the preferred idiomatic approach to implementing error types hasn't stabilized. However, that "churn" has all been in third-party crates, so

> 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.


`Box<dyn Error + Send + Sync>` is almost always fine


What was worse about Rust 1.0's error handling that, say, Typescript's Result? They look very similar to me.

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.


Composing first-class functions is much more idiomatic in typescript, because there's only one function type, so you can do the railway-oriented programming style. In a sense Rust doesn't quite have first-class functions yet (and I'd argue that NLL actually made functions less first-class than they were before): you can't always pull out a given block of code into a closure, because the resulting code may not pass the borrow checker. Whereas in Typescript (() => x)(), (a => x)(a) etc. are always equivalent to x.


That's true but that seems to be an inevitable consequence of the Rust ownership model. Which means this is just another example of where the "one big innovation" in Rust just isn't orthogonal to other language design issues, as you suggested it should be.


To a certain extent yes, but it's a problem that they've made much harder for themselves by trying to support both OCaml-style first-class functions and C/Java-style imperative control flow. If the NLL work around control-flow keywords had gone into first-class functions, I suspect we'd see a good solution by now; conversely if they'd committed to C++/Java style with what works there (i.e. exceptions) that would also probably make for a result that was easier to use.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: