5 ms·
> Continuations and the way Erlang handles this have far less mental overhead and help keeping the model and the mental representation of that model in sync. Di
by insanitybit 3y ago
> Continuations and the way Erlang handles this have far less mental overhead and help keeping the model and the mental representation of that model in sync. Differences between the two is where bugs will hide.
You still have a lot to think about in Erlang. For example, you need an entire supervisory system to handle the fact that an actor can die. You need to handle the fact that an actor A might send a message to actor B and not get a response, or it'll get a response way later. You need a native way to link actors, a native way to name actors, a tracing system, etc. Actors are not something you can simply slap onto a system and suddenly you've got Erlang superpowers.
TBH tokio tasks give you a very similar abstraction without the problems - you can join a task. That's a huge ergonomic improvement because you can isolate/join state at will without having to use a channel.
> it's an ugly wart on Rust and a distraction to boot.
It's really not that bad. Like, IMO the major reason to have async is for cancellation. I want to be able to have a network request time out. That is way, way easier to handle in async code than threaded code. The best I can do with a sync system is specify timeouts on an underlying resource like a socket, I can't do anything like "this specific request should have this specific timeout" without async.
- jacquesm 3y agoThe supervisory system is an extra, you don't technically need it but it can help make your application bullet proof and I would definitely recommend if you go the Erlang route to use it to your advantage. Every other language and/or runtime will need something similar anyway, but there is a good chance that it won't be nearly as elegant (as as solid) as the way Erlang does this. Agreed that actors are not something that you can slap onto an existing system, but you can build systems that use a lot of those lessons effectively without them being written in Erlang. > It's really not that bad. Like, IMO the major reason to have async is for cancellation. I want to be able to have a network request time out. That is way, way easier to handle in async code than threaded code. The best I can do with a sync system is specify timeouts on an underlying resource like a socket, I can't do anything like "this specific request should have this specific timeout" without async. That's a great way to end up with orphaned resources though. If you kept it at the process level that simply could never happen, your process would error out, the supervisor would take over and that would be that.
- insanitybit 3y ago> The supervisory system is an extra, you don't technically need it but it can help make your application bullet proof and I would definitely recommend if you go the Erlang route to use it to your advantage. An actor system without supervisors is throwing away a lot. How do you handle an actor that crashes? The thing is, again, Actors are very low level - they're a foundational model. You end up having to build protocols and systems on top. > If you kept it at the process level that simply could never happen, your process would error out, the supervisor would take over and that would be that. I don't think you're going to get an orphaned resource by timing out and dropping the future, which drops its state.
- bombela 3y agoI am responding to the very last point about dropping a future and the resource usage. Let's assume a future that implements reading from a network socket. And the file descriptor (fd) was already passed to epoll/select (I am ignoring io_uring). After dropping the future, the socket is is still being considered by the kernel for reading. Eventually epoll will return, and the IO runtime (like tokio) will notice the stray fd and discard it. And can you even close the fd before it is out of epoll? So until the fd is back to user land, it appears very similar to leaking resources. Even if only for a short time while the IO loop is completing an iteration.
- insanitybit 3y agoI'm not sure how an actor would solve that problem. You're describing the way a system call works, which is not relevant to how your userland asynchrony works. In either case you're always "leaking" (I'd say "holding") the resource while you wait for the kernel to give it back to you.
- bombela 3y agoIndeed I was merely describing how it behaves within the context of future + ioloop with tokio. I didn't take a stance on future vs actor. In Rust my instinct tells me the difference between actor and future is negligible. Because it compiles down to almost the same thing. But I wouldn't bet my life on it. Note that my understanding of what an actor is might be wrong. I assume an actor is a sort of thread with a main ioloop receiving and sending messages. Which is basically what a tokio ioloop thread is. Atop of which the futures give you an abstractions to compose IO functions more easily.
- pdimitar 3y agoYou seem to be mostly arguing that all the building blocks are in place and you can assemble your own LEGO. Which is exactly what I started disliking lately. I want async Rust more opinionated with much more huge red arrows pointing in the right directions for cases A, B and C, and links to docs and even 3rd party crates for cases from D to Z.