Yoshua Wuyts, a Rust async working group member, writes about async Rust, error handling, effects, and language design ideas.
Commenters discuss its Rust error handling overview and async posts, debating Rust's many error libraries versus Go's convention, and what async is for.
> Not sure what's meant by this; Rust has a standardized Result type, with dedicated syntax for early-returning errors and type checks that make sure you handle them (or at least explicitly ignore them). Go, on the other hand, has a shaky error story and from what I've heard it's a constant problem due to enforcement-by-convention.
You may not like Go's convention (indeed, I don't love it although I think it works fine in practice), but the only error handling mechanism in Go is `if err != nil { ... }`. On the other hand Rust has many. This is not incompatible with your observation of "a standardized Result type". Here is a survey of the error handling landscape circa 2019: https://blog.yoshuawuyts.com/error-handling-survey/
> Not really sure what this means either... the owner of a value generally falls out naturally from how you're trying to use it. It's not really an either/or option
Or you have code which clones gratuitously out of convenience, often because some API unnecessarily asks for ownership of its arguments. Cloning is often just easier than battling the borrow checker, so in the real world with its deadlines, we tend to see a lot of clones because it's more convenient and performance is rarely a concern.
> I've seen generics make TypeScript codebases impenetrable, and I think there's a decent case to be made for not having them at all.
In fairness to TypeScript, I suspect much of this 'impenetrability' is because type annotations were added to existing…
I don't think a good conversation can be had if we start by arguing about whether or not "rust's strategy has to be the only way to achieve memory safety".
There are other ways to achieve memory safety. Java's strategy is definitely a valid one; it's just not as suitable for systems programming. The strength of Rust's approach ultimately stems from its basis in affine types -- it is a general purpose and relatively rigorous (though not perfect, see https://blog.yoshuawuyts.com/linearity-and-control/) approach to managing resources.
One implication of this is that a point you raised in a message above this one, that "rust's default heap allocation can't be trivially used", actually doesn't connect. All variables in Rust -- stack allocated, allocated on the heap, allocated using a custom allocator like the one in Postgres extensions -- benefit from affine typing.
It’s hard to say. If you want to use green threads, you may want to look at the may crate [1]. The reason Rust prioritized stackless async just like C++ did is that it fits better the systems programming needs (i.e. it’s syntactic sugar for a state machine you could hand implement) while not preventing things like stackful coroutines.
If Rust manages to solve the coloring problem of async (e.g. by adopting effect systems [2] or alternatives), then stackful and stackless coroutines syntactic sugar could conceivably exist within the std language (perhaps leaving out stackless on nostd).
The reason you don’t see both stackless and stackful coroutines in a single language like Rust is the coloring problem is made 50% worse.
[1] https://crates.io/crates/may
[2] https://blog.yoshuawuyts.com/extending-rusts-effect-system/
> any blocking operation (a method where Ruby interpreter waits) is compatible with Async and will work asynchronously within Async code block with Ruby 3.0 and later.
That's pretty magical. Does this mean it would be possible to implement structured concurrency [0], but without the function coloring problem?
Regardless, I think I prefer how this looks from a code read/writeability perspective compared to Zig's or Swift's (and potentially future Rust's [2]) approaches.
[0] https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful
[1] https://kristoff.it/blog/zig-colorblind-async-await/
[2] https://blog.yoshuawuyts.com/async-overloading/
I have good news for you then-- there already is some experimental[0] work towards this, under the name of "pattern types" (although I believe it's on pause at the moment). The idea seems to be to pull some of the pattern semantics into the type system, allowing for more than just range types, based on a series of blog posts[1] by the author of the PR. Additionally, Yoshua Wuyts has another blog post[2] which gives a decent intro on the concept and what it could be used for down the line.
[1]: https://github.com/rust-lang/rust/pull/107606
[2]: https://cohost.org/oli-obk/post/165584-ranged-integers-via
[3]: https://blog.yoshuawuyts.com/pattern-extensions/#pattern-types
> You may not like Go's convention (indeed, I don't love it although I think it works fine in practice), but the only error handling mechanism in Go is `if err != nil { ... }`. On the other hand Rust has many. This is not incompatible with your observation of "a standardized Result type". Here is a survey of the error handling landscape circa 2019: https://blog.yoshuawuyts.com/error-handling-survey/
By this definition, Go has many too. Go has lots of libraries to wrap error types, combine errors, preserve error data, etcetc.
Errors are one of the more similar things between Rust and Go, honestly.