3 ms·
The naming is a little confusing here. This is Actix the actor model library, not "Actix web" the web framework that's usually discussed. Originally "Actix web
by dmm 7y ago
The naming is a little confusing here. This is Actix the actor model library, not "Actix web" the web framework that's usually discussed.
Originally "Actix web" depended on Actix the actor library, but no longer. Though they can be used together. And I think websockets still require actors?
I'm using both Actix and Actix web for a personal project. I like it a lot and think the actor model is good fit for applications that don't fit well into a request lifecycle.
My main pain point with it is the use of futures. Right now it's a huge pain to have more than one return value in an Actor Handler, the functions that handle actor messages. Even if you box the returned Future, you end up having to use futures::Either a bunch and when you mess it up you get tons of confusing errors filled with the huge inferred types.
Implementing something like:
if (condition1) {
return <future for service call1>;
} else if (condition2) {
return <future for service call2>;
} else {
return <no-op future>;
}
Is a big pain requiring two layers of future::Either. Or I just don't know what I'm doing, which is very possible.
async/await would be a huge improvement, but can't be used at the moment, even though the current version of Actix uses std::future's.
- aphexairlines 7y agoCan't you use async/await with the compat libraries for futures and for tokio? https://tokio.rs/blog/2019-12-compat/ https://tokio.rs/blog/2019-12-compat/
- kevinmgranger 7y ago> Even if you box the returned Future, you end up having to use futures::Either a bunch That's really strange. A Boxed future is the end-all-be-all of not caring about the underlying type. Would you mind sharing a snippet of code that shows where you need both a Boxed future and Either?
- dmm 7y agoYou're probably right, I must be missing something. I'm also still on futures 0.1 because I'm still porting it to std::futures. Here's an example of what I was discussing: https://github.com/dmm/exopticon/blob/c40d14c80c150ef62707320085b8f9243160c8a8/exopticon/src/camera_routes.rs#L245 https://github.com/dmm/exopticon/blob/c40d14c80c150ef6270732... The idea is that I want to implement a relative ptz move on a camera but some cameras have a broken relative move implementation so in that case we instead use a continuous move + a delay + a continuous stop. The final case is when a camera has no ptz it returns Http::NotFound.
- Arnavion 7y agoIf you have if cond { Box::new(future_a) } else { Box::new(future_b) } then by default, the type of the first Box will be concrete Box<FutureA> rather than Box<dyn Future>, which is why you'll get a type error that Box<FutureB> != Box<FutureA> You'll need to coerce the first expression to Box<dyn Future>. The compiler will auto-coerce the other one. if cond { Box::new(future_a) as Box<dyn Future<...>> } else { Box::new(future_b) } See https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=cd2d3fe1b68d430f1de3f0d4ad8ec3ac https://play.rust-lang.org/?version=stable&mode=debug&editio... (This auto-coercion also applies to other situations where the type of an expression must match the previous one's, such as with a slice literal where the first element dictates the types of the rest.) You don't need to coerce if the compiler can infer that the whole if-expr must be of Box<dyn Future> type. This happens when the if-expr is being returned directly and thus must have the same type as the function's return type, or it's being assigned to the binding and the binding has been previously inferred to have (or explicitly has) Box<dyn Future> type. You can test this in the playground by returning the if-expr directly instead of binding it to `result`.
- estebank 7y agoA more stylistic pattern for this is to give the binding a type so that the coercion of the if/else expression works automatically instead of using `as`. Also, there's work being done so that this won't be needed by deferring evaluation of expressions until the whole body has already been evaluated so that inference with the naïve code will work at some unspecified time in the future.