Tinder / StateMachine

A Kotlin and Swift DSL for finite state machine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

State machine's dontTransition() method

uburoiubu opened this issue · comments

Hi, I really appreciate your implementation of state machine.

I have one question though: you have this method called dontTransition() which makes the state machine reenter the same state. What would be the way to workaround this and not reenter the same state? Is there something like ignoreEvent() method?

Thanks.

@uburoiubu Did you want to stay in the same state without emitting a transition?

@zhxnlai, yes, I did.

@uburoiubu I don't think we need an ignoreEvent method because

  1. although dontTransition returns an identity transition, it can be filtered afterwards.
onTransition {
        logger.d("received unexpected event ${validTransition.event}")
        val validTransition = it as? StateMachine.Transition.Valid ?: return@onTransition
        if (validTransition.from == validTransition.to) {
                logger.d("received expected event ${validTransition.event} but did not change state")
                return@onTransition
        }
        logger.d("received expected event ${validTransition.event} and changed state")
        // ...
}
  1. ignoreEvent is less debuggable because you would need to write more code to intercept events

@zhxnlai, thanks. Could you elaborate more on the convenience ofdontTransition() command? as far as I understood, it is more like reenterThisState(). Or not?

Suppose I don't write the following declaration:

on<Event.OnConfigChanged> { dontTransition() }

then it is an invalid transition for state graph, but on the other hand, we stay in the same state.

If I write it, I reenter the same state, although I write dontTransition(). It is a little misleading in terms of naming.

Thanks again.

I had the same reaction and was surprised when dontTransition ends up causing an identity transition. I eventually ended up doing the filtering suggested above, but fixing things this way did make me wish that StateDefinitionBuilder.on had some overloads with varying amounts of generic values for the handled events; I have a lot of situations like the following:

state<MyState.SomeState> {
  on<Event.InterestingEvent> {
    transitionTo(MyState.OtherState)
  }
  on<Event.NoOpEvent1> {
    dontTransition()
  }
  on<Event.NoOpEvent2> {
    dontTransition()
  }
  on<Event.NoOpEvent3> {
    dontTransition()
  }
}

where it'd be nice to be able to do:

state<MyState.SomeState> {
  on<Event.InterestingEvent> {
    transitionTo(MyState.OtherState)
  }
  on<Event.NoOpEvent1, Event.NoOpEvent2, Event.NoOpEvent3> {
    dontTransition()
  }
}

I tried to accomplish something like this using Matcher, but since its constructor is private I couldn't. Maybe there's another way I'm missing?

Actually, I was just looking at Scarlet's usages of the state machine and saw this usage

private fun lifecycleStart() =
            any<Event, Event.OnLifecycle.StateChange<*>>().where { state == Lifecycle.State.Started }

which looks like that should make this possible, so I'll play with that a bit.

unfortunately it seems that the dontTransition() method also causes the onEnter to be called for the state. Haven't found a great way around this yet.

commented

I am with you @ThomasDotCodes, I do have events in my state machine, where I need to execute some code but not transition. This behaviour triggering the onEnter is making it hard to achieve what I want. I am having to write all the onEnter code under onTransition when I detect a state change.