svelte-fsm icon indicating copy to clipboard operation
svelte-fsm copied to clipboard

Eventless transitions

Open kenkunz opened this issue 2 years ago • 5 comments

Opening a new issue to consider / discuss the possibility of adding Eventless Transitions, as proposed by @morungos:

Originally posted by @morungos in https://github.com/kenkunz/svelte-fsm/issues/8#issuecomment-1237430403

I'm just following up on my to-do list. Turns out, that second commit I removed earlier, which was about adding eventless transitions, has been incredibly useful (aka, more or less essential) to our project, and they weren't hard to add in. If you're interested, check out: https://github.com/morungos/svelte-fsm/commit/0955042122b95f94cfca9b62f574e5f23ed92200 I'd be more than happy to make that a pull request too (we don't really want to maintain a fork), but if not, it can stay independently where it is.

Proposed feature / API change

The proposed change is to allow _enter lifecycle actions to return a new state, which may result is a chain of synchronous state changes from a single event invocation. Subscribers would only be notified after the final state change (and only if the resulting state is different that the pre-event state).

kenkunz avatar Sep 08 '22 22:09 kenkunz

I am open to considering this, but I have some initial hesitancy and would like to understand the potential use case(s) better.

My hesitancy is that this adds a lot of complexity and (imho) makes an fsm more difficult to reason about. With the current behavior, an event invocation results in 0 or 1 state changes, and it's easy to follow the causal sequence. With this change, an event invocation could result in arbitrarily many state changes, making it far more difficult to follow the causal chain.

This also opens the door to strange edge cases that would need to be dealt with – e.g., an infinite state change loop.

@morungos (or anyone else interested in this feature) – can you share more about the use cases / scenarios that are driving this request?

Thanks!

kenkunz avatar Sep 08 '22 22:09 kenkunz

Sure. Our main use case was the navigation state in a component. We want the application to be able to, for example, go to the login state, but if it is already logged in, to automatically transition to that state without some derived store having to somehow to swallow the additional states, which might trigger fast renders of components before it settled into a final state. In effect, directing to a login state might transiently flash a login screen even if you're already logged in. We did attempt to use a derived store to skip transitional states but turned out to be somewhat more complex than the entire FSM, and it required unpacking the states into pre-states so we'd know when to ignore. In effect, we would have needed to restructure the state design significantly to make it possible, and even then we'd have a substantially more complex system, with very tight coupling between these two components, when really all we needed was to hide transitory states from the application.

There are other examples, but they were more or less equivalent -- in every case we wanted to be able to request a state, and then, if certain guard conditions were met, eventlessly fall through into a more appropriate state (each state more or less corresponded to a screen) without rendering all the screens along the way.

xstate, for example, does have eventless transitions -- in its full version -- and they are an accepted part of state charts.

Our logic pretty much followed the state charts description: we always need to guarding against certain conditions. And yes, there absolutely is the risk of creating an infinite loop if you get it wrong. There's a warning to that effect on the xstate pages. In fact, there is anyway, even if you attempt to achieve that with a derived store. In fact, it's worse with a derived store because you're now fighting Svelte's stores as well as the FSM.

But, of course, we'd far rather use this module than xstate, which would more or less double our deployment footprint for this one small requirement.

morungos avatar Sep 13 '22 15:09 morungos

I am open to considering this, but I have some initial hesitancy and would like to understand the potential use case(s) better.

My hesitancy is that this adds a lot of complexity and (imho) makes an fsm more difficult to reason about. With the current behavior, an event invocation results in 0 or 1 state changes, and it's easy to follow the causal sequence. With this change, an event invocation could result in arbitrarily many state changes, making it far more difficult to follow the causal chain.

This also opens the door to strange edge cases that would need to be dealt with – e.g., an infinite state change loop.

@morungos (or anyone else interested in this feature) – can you share more about the use cases / scenarios that are driving this request?

Thanks!

Hi, has there been any movement towards implementing eventless transitions?

jakubdonovan avatar Sep 30 '22 03:09 jakubdonovan

@morungos thanks for sharing the details above – this was very helpful.

I'm working to implement this. For consistency, you will be able to return a state from _exit or _enter. Transitions will be followed until no transitions are returned, so you could transition through many states from a single event invocation. I am leaning towards also supporting internal transitions (i.e., transitioning to the current state will still invoke _exit and _enter).

I'll push a public branch soon for feedback.

kenkunz avatar Oct 02 '22 03:10 kenkunz

@kenkunz You might want to look at: https://github.com/morungos/svelte-fsm/commit/0955042122b95f94cfca9b62f574e5f23ed92200, which was my implementation. There's also a few tests. It might give you some ideas.

morungos avatar Oct 02 '22 16:10 morungos