Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A macro to generate message handler boilerplate #469

Open
piegamesde opened this issue Feb 27, 2021 · 1 comment
Open

A macro to generate message handler boilerplate #469

piegamesde opened this issue Feb 27, 2021 · 1 comment

Comments

@piegamesde
Copy link

When adding messages to an actor, I noticed that it very often follows some specific pattern, that involves a bit of boilerplate code:

  • Create the method that does something on the impl MyActor
  • Create a struct that represents the arguments of that method and derive actix::Message for it
  • Implement actix::Handler<SomeMessage> for MyActor by having the handle method delegate to the associated method

I have the idea of reducing the boilerplate (and the number of structs) involved by having a proc-macro generate most of it. A first step towards this, which only automates the impl Handler, could look like this:

impl MyActor {
    /* Simple case */
    #[handler(SomeMessage)]
    fn update_content(&mut self, event: SomeMessage, ctx: &mut Self::Context) { todo!() }

    /* The macro needs to parse the return type from the method for the trait implementation */
    #[handler(SomeMessage)]
    fn update_content(&mut self, event: SomeMessage, ctx: &mut Self::Context) -> SomeResponse { todo!() }

    /* Optional: if the function is `async`, automatically wrap `<MyActor as Handler<SomeMessage>>::Result` in a future */
    #[handler(SomeMessage)]
    async fn update_content(&mut self, event: SomeMessage, ctx: &mut Self::Context) -> SomeResponse { todo!() }
}

A second step then would be to somehow extract the function arguments into their own struct. I am sorry that I cannot prototype this myself, as I don't have enough proc macro skills.


Motivation: I am working on a GTK application using woab. GTK uses a lot of signals and handlers, resulting in a lot of boilerplate code. Therefore, woab currently exposes all signals as variants of one message enum. But I think that having a proper message per signal type would be more idiomatic.

@fakeshadow
Copy link
Contributor

fakeshadow commented Feb 27, 2021

I find derive or proc macro offer almost nothing in actix's case. You seem to write less code(Arguably a couple of lines) with them but it's just pushing the cost to code generation at compile time which would be obvious if you have many of them.

With your macro you also likely to lose type infer in IDEs where your SomeMessage attribute can not figure out if SomeResponse is have the right Message::Result type map to Handler::Result as MessageResponse.

The async fn is also a bad idea. Doing that would force everything wrap inside a future. Making you can not practice the general pattern of sync code first, return a future after.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants