anduintransaction/scala-fsm

Unable to put Fsm instance in another class that doesn't have type parameter

Opened this issue · 2 comments

The Fsm[_] class is type parameterized, so while doing this works:

    case class Foo[S <: State](fsm: Fsm[S])

    "test Foo" in {
      val x = Foo[A](Fsm(A("a")))
      val y = x.copy(fsm = x.fsm.transition(Iab("b")))
      y.isInstanceOf[Foo[B]] shouldBe true
    }

This doesn't work:

    case class Bar(fsm: Fsm[_])

    "test Bar" in {
      val x = Bar(Fsm(A("a")))
      val y = x.copy(fsm = x.fsm.transition(Iab("b")))
    }

Compile error:

[error] could not find implicit value for parameter t: anduin.fsm.Transformation[_$1,Iab,TO]
[error]       val y = x.copy(fsm = x.fsm.transition(Iab("b")))

Because of this fact, I'm unable to put the Fsm[_] in a React case class State 😞

/cc @nhap96 & @ngthanhtrung to see if there's anything we could do to improve this

Thanks for the FSM implementation.

Lets say I have List(Input) where I have to loop thru each Input record and depending on previous state, transition to next state based on some conditions.
How do I implement this based on your FSM. Thanks in advance.

Example:

case class TuningEvent(eventType:String) extends Input

case object NONTUNED extends State
case object TUNED extends State
case object TRICK extends State

implicit val t_NONTUNED_TUNED = Transformation1[NONTUNED.type , TuningEvent , TUNED.type]((_, ) => TUNED)
implicit val t_TUNED_TRICK = Transformation1[TUNED.type, TuningEvent, TRICK.type]((
, _) => TRICK)

val inputList = List(TuningEvent("PLAY"),TuningEvent("REPLAY"))

var newFsm = Fsm(NONTUNED) // Begin with NONTUNED always
for (input <- inputList) {
println(newFsm.transition(input))
}

My expected output should be

Fsm(TUNED)
Fsm(TRICK)

But Actual Output:
Fsm(TUNED)
Fsm(TUNED)

@nats82 thanks for trying our this project.

The reason for the output you see is that you always invoke transition() from the same object (which is newFsm), hence receiving the same output. You will need to invoke transition on the returned Fsm of a transition, e.g. newFsm.transition(TurnEvent("PLAY")).transition(TurnEvent("REPLAY")) will yield Fsm(TRICK).

Looping through a list of TuningEvent won't work yet, and the reason is that everything is checked at compile time, but at compile time, you don't know how many TuningEvent are there, hence the compiler can't determine what the final state of the Fsm will be. The root cause of this is the same as the problem I described above, and unfortunately, we don't have an answer for that yet. This might be an example of pushing too far into an extreme (everything is statically checked), and make it not usable in practice 😞