Hacker News new | ask | show | jobs
by littlestymaar 1089 days ago
> Let’s not make this discussion so rust-specific

But this is a discussion about Rust! And my entire point is that async/await is entirely consistent with Rust's overall design.

> But exceptions (especially checked exceptions like in java) don’t have that problem, and are exact analogues to Result types.

Unchecked exceptions don't have this problem (but checked exceptions do), and that's exactly my point. Async/await vs green-thread is exactly the same trade-off than Result vs exceptions: one is “simpler to use”, the other is “simpler to read”. After years of programming, I personally came to the conclusion that we spend more time reading code than writing it (and it's going to be even more true in the near future with LLMs) so I lean on the Result/await side of things, but I don't have fundamental objections against green thread and exceptions.

I do have a fundamental objection against the idea that “async” is somewhat special.

> This is not true of async/blocking — there can be semantic differences between two, otherwise equivalent implementations

Result vs exceptions have also a significant semantic difference: unwinding, and especially the fact that you can trigger unwinding at any point. This is a significant issue when you're dealing with pointers.

> how should an async-block-async call chain work exactly?

I don't really understand this question. An async function is just a regular function that returns a Future, and yes since there's no marker for blocking function you can definitely call one inside an async context, even though it's often a very bad idea from a perf PoV (well it depends, locks are mostly fine, but you need to use them with caution).

In fact, the `async` marker in functions doesn't bring much (again “async function are just regular functions that return a Future”), and it would make much more sense to have a `blocking` stack-contaminating marker on function that call a blocking syscall in order to avoid performance problems due to those, but we can't have nice things because something Path Dependence something…

1 comments

I’m talking about checked exceptions — they are absolutely analogous to a Result<ReturnType, ExceptionType> in Rust, that is they are part of the type signatures. It is no longer the example you are talking about re panics vs Result.
Checked exceptions are indeed similar to Result, but as such they also have the same issue of “coloring” the call stack, so I don't really see what's the argument you're making here…
My whole point: error handling is decided at the caller-end trivially. They can try-catch/use ?/just unwrap, whatever it doesn’t concern the implementation. Async/blocking is not like that, as it can itself recursively contain similar “decision-points”, and the final caller cares about all of them, as it might change semantics.
But if you catch an error in the middle of the call-stack, then the caller don't have access to this error, so this has the exact same semantic implication as well! And the final caller would sometimes care about that, but no luck, yet I've never seen anyone complaining about how `catch` is terrible for that reason…

Of course it doesn't happen too often, but nor does your recursive async/blocking function example (been using async/await for a decade now, and I've never encountered the issue in actual code) and I suspect that for most purpose, using `block_on` in the blocking function is the sensible thing to do, and it has the same role as a `catch`: the upper function has no way to know there was actually some async stuff under the hood.