dart-statemachine icon indicating copy to clipboard operation
dart-statemachine copied to clipboard

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

Open svk014 opened this issue 2 years ago • 7 comments

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?

svk014 avatar Jan 18 '22 21:01 svk014

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.

renggli avatar Jan 18 '22 21:01 renggli

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

svk014 avatar Jan 18 '22 21:01 svk014

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'
}

renggli avatar Jan 18 '22 21:01 renggli

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.

svk014 avatar Jan 18 '22 22:01 svk014

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

renggli avatar Jan 19 '22 14:01 renggli

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

  • Adding C per State would make the API really ugly. At many places where the type would not be know the return type would need to be State<I, dynamic>.

  • Adding C per Machine would make the API slightly less ugly, but much more restrictive. Probably not useful to force all states have the same generic context type?

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

renggli avatar Jan 19 '22 17:01 renggli

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.

svk014 avatar Jan 19 '22 17:01 svk014