renggli / dart-statemachine

Simple, but generic state machine framework for Dart.
http://pub.dartlang.org/packages/statemachine
MIT License
78 stars 10 forks source link

How do we send data to another State when activating it? #13

Open svk014 opened 2 years ago

svk014 commented 2 years ago

Consider two states StateA and StateB. StateA has a transition inside which a method mA1 is executed and it produces some object o1. After, mA1 is executed, we set the current state to StateB. On entering StateB, we need to call another method mA2 with the previously produced object o1.

How do I achieve this? I think this can be achieved using Streams, but is that the best solution?

renggli commented 2 years ago

This library doesn't enforce a specific way to model or pass data.

The most strait-forward way would be if you stored the object in a variable that both handlers have access to.

A more generic way would be to use custom state objects, and use a transition handler to propagate the value from the previous state to the next one.

svk014 commented 2 years ago

Can you please give me an example of the transition handler approach?

renggli commented 2 years ago
class Data {
  String? input;
  String? output;
}

void main() {
  final machine = Machine<Data>();
  machine.onBeforeTransition.forEach((event) =>
      event.target?.identifier.input = event.source?.identifier.output);

  final stateA = machine.newState(Data());
  final stateB = machine.newState(Data());

  stateA.enter();
  stateA.identifier.output = 'Hello';

  stateB.enter();
  print(stateB.identifier.input); // Prints 'Hello'
}
svk014 commented 2 years ago

What do you think about state.enter() accepting an argument? Something along these lines,

State<Data, Custom?> stateA = machine.newState<Custom?>(Data()); 
Custom? customObject;
stateA.enter(customObject);

Internally, the state can hold the data as T? input, and it can clear it by setting input = null in an exitTransition.

renggli commented 2 years ago

That sounds like a useful idea, if the typing doesn't get too messy. I have to think about this a bit more.

renggli commented 2 years ago

State<I, C> where I is the type for the identifier (present today), and C is the type of the context (or mutable data).

In either case the API would not be backward compatible (adding a generic type is breaking this). Any other ideas?

svk014 commented 2 years ago

I agree that this would be not backwards compatible. Adding C per State would make the API more useful, but like you said, things like machine.current would have to return State<I, dynamic> which kind of defeats the purpose.