digint/tinyfsm

Transit only if not already in state

davidgraeff opened this issue · 4 comments

Would it make sense to add a transitIfNotIn method next to transit, that prevents calling entry and exit? Like so:

  template <typename S> void transit(void) {
    current_state_ptr->exit();
    current_state_ptr = &_state_instance<S>::value;
    current_state_ptr->entry();
  }

  template <typename S> void transitIfNotIn(void) {
    if (current_state_ptr == &_state_instance<S>::value)
      return;
    current_state_ptr->exit();
    current_state_ptr = &_state_instance<S>::value;
    current_state_ptr->entry();
  }

Example usage:

virtual void react(NoWifiEvent const &) { transitIfNotIn<LostWifiState>(); }

I don't think this makes sense, as it would break the state machine rules: a transition always exits the current state, then enters the new state (that's why you draw an arrow for self transitions).

Can't you just handle the NoWifiEvent differently in LostWifiState:

class LostWifiState
: public MyWifiFsm
{
    void react(NoWifiEvent const &) override { };
}

If you really want to break the rules, you could still use:

virtual void react(NoWifiEvent const &) {
    if(!is_in_state<LostWifiState>()) 
        transit<LostWifiState>();
}

You are right, that it it possible to model the automata in a fully deterministic way (like in https://en.wikipedia.org/wiki/Finite-state_machine#Determinism).

In my usecase I'm forwarding the wifi state as an event to the FSM, so it is called in every loop cycle. It saves quite some OPs to not enter and exit this state (and the event can be handled in a non virtual function, so no vtable lookop on top).

The transitIfNotIn allows me to model a non-deterministic automata with no state change for the same event.

If you say, tinyfsm is for deterministic FSM then it would be a bad idea to add it of course.

No, I'm not saying TinyFSM is for deterministic FSM only. By using the bool is_in_state<S>() or S & state() functions, or by manipulating current_state_ptr you have all means to make it non-deterministic.

My goal is to keep it "as simple as possible", and adding additional comfort functions like transitIfNotIn<S>() contradicts to this paradigm, as this functionality is already available by using is_in_state as described above (which comes with no performance penalty).

Actually, it would be nice to have a simple, meaningful example in TinyFSM which operates non-deterministic.

Makes sense :)