pierremrtn / state_machine_bloc

An extension to the bloc state management library which lets you create State Machine using a declarative API.
MIT License
38 stars 5 forks source link

[Discussion] Any reason to not make transitions async? #7

Open proshin-roman opened 1 month ago

proshin-roman commented 1 month ago

Hi @pierremrtn!

Thank you for a handy library! I also faced a problem with BLoC where one of the BLoC's became too big, and transitions got out of control - converting that BLoC into a state machine appeared to be the smartest option.

While integrating your state_machine_bloc, I noticed that transitions may only be synchronous functions, while with BLoC it's totally fine to make them async - since the handling of events happens in the background, it shouldn't be a problem.

I'm playing around with the library locally, and it looks like it's not a big deal to convert transitions to async functions. But since the docs don't mention anything regarding that decision, I thought I better ask you if there is anything that would enforce having no async. What would be your opinion on that matter?

Example:

pierremrtn commented 1 month ago

Hello, thank you for your feedback! I've spent quite a lot of time thinking about the best way to architect and define state machines, but I'm not settled yet, hence the lack of updates on this package. Allowing futures in transitions raises the question of concurrency. With sync transitions, there are no questions; they are evaluated in the order of definition. Can you please describe your use case? That would help in considering options.

proshin-roman commented 1 month ago

The use case is quite common, I guess - loading data from the remote API: when I switch to state X, I need some data for the state that is loaded asynchronously. And because the transition cannot be async, I now have two nested states: the first one - X-a - that appears immediately, then using the onEnter for that state, I load the necessary data and once it's loaded, I fire an event that switches state X-a to X-b that then contains the loaded data. That's exactly what you describe in the Nesting states section of the documentation.

If I could make the transition asynchronous, I would load all the data right in the transition to state X:

Speaking about concurrency: looks like it's already a part of the equation anyway - Events concurrency, and it's also one of the differences between BLoC for "clean Dart" (Cubits) and BLoC for Flutter.

pierremrtn commented 1 month ago

So, if I follow you, you would like to be able to do something like:

define<StateA>(($) => $
  ..on<SomeEvent>((event, state) async {
    try {
       final res = await apiCall();
       return StateB.success(res);
    } catch (e) {
       return StateB.error();
    }
  })
);
define<StateB>();

By the way, are you using nested states at all? Because with new language features we're able to do this:

on<Event>((e) => switch (state) {
   StateA() => switch(e) {
      EventA() => emit(StateB()),
      _ => (),
   },
   StateB() => switch(e) {
      EventB() => emit(StateA()),
      _ => (),
   }
});

To be honest, it's been so long since I've worked on this that I didn't remember all the implementation details. I'm not even using it myself anymore (I even unlisted it from pub.dev). But it looks like there are a few people interested coming sometimes, so I'm hesitating on taking a new take on this.

Any thoughts/feedback beyond the async transition would be welcome. If the package has real value, then I may invest time into it again.

proshin-roman commented 1 month ago

Yes, exactly as you showed in the first snippet - I would like to be able to await inside the transition function as that simplifies quite a lot of things, e.g., it eliminates the need to have intermediate states like "loading"/"loaded". As I already mentioned, I actually modified the library locally so that I can use it in my pet project, and it seems to be working OK (I also pushed these changes to my fork of the repo).

I'm quite new into state machines, so I don't really have other ideas for now, but in case they appear, I will post them here.

I also think that the package can be safely published on the pub.dev - looks like it doesn't need that much maintenance as it only depends on BLoC and Flutter itself.

pierremrtn commented 1 month ago

I've though about it, I think it is fine to allow async in transitions. I'll take a look at the implementation you provided, thank for that btw. Shouldn't be that long to do the change, stay turned