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

Ractor is cool, but I've been wondering why it uses the async `async_trait` rather than native async traits. Is it just because it came out before async traits were stabilized, and now code relies on it and it would be a breaking change to migrate?

For context, the `async_trait` crate makes futures from trait methods that are wrapped in `Pin<Box<dyn Future<...>>>`, which means that every async call to a trait method must make a heap allocation. This is currently a necessary thing to do if async trait methods were invoked with dynamic dispatch (through `dyn Actor`), but the `Actor` trait has associated methods, so that is already not generally possible.

I realize that methods on the `Actor` trait return futures that are `Send`, but specifically for an actor framework that feels like a very specific design choice that isn't universally good or necessary. Another design would give let the spawned task that executes the actor's messages exclusive access to the actor (so `handle()` could take `&mut self`).

I've ended up implementing a simple alternative design in my own project (it's not fundamentally very hard, but doesn't have all the features, like supervision) because the per-message heap allocations and internal locking became wasteful for my use case.



> I've been wondering why it uses the async `async_trait` rather than native async traits

From their crate documentation[0]:

> The minimum supported Rust version (MSRV) is 1.64. However if you disable the `async-trait` feature, then you need Rust >= 1.75 due to the native use of `async fn` in traits.

[0]: https://docs.rs/ractor/0.13.0/ractor/index.html




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

Search: