https://kotlinlang.org logo
Title
u

ursus

11/17/2018, 5:39 PM
About statemachines? If I have certain actions, which are allowed in certain state, where they dont change it state, however those actions are async, so need to change "some" state to pending, in order to avoid multiple calls until the async is finished i.e. I have call states, for example one of which is Activated, and I have actions like MuteMic, where this action is only allowed in Activated state but lets say MuteMic is heavy / or async, so I need to surround it with pending state, should that pending state be part of the call state hierarchy, i.e. on the same level as Activated is, or somehow nested inside it, or separate state machine?,
when state == Activated
   when action == MuteMic
      state = ActivatedMuteMicPending
      effect(Effect.DoMuteMic)
      state = Activated
sealed class State {
   object Activated,
   object ActivatedMuteMicPending
}
im not sure if this is good design
l

louiscad

11/17/2018, 6:43 PM
The snippet with
when
can't compile to begin with
u

ursus

11/17/2018, 7:20 PM
obviously, syntax is not the point
t

Timmy

11/18/2018, 12:43 AM
What do you want the state machine to do when it is in a pending state? If it has to wait anyway before the next action, what purpose does the pending state have? On the other hand, if the next action is independent of whether muting the mic is pending or not, I would split the muting into a new state machine. That is if state machines are the correct way to model this logic. They can get quite complex really fast unless care is taken to keep the amount of states at a reasonable amount. Also, any reason you are using a sealed class instead of an enum?
u

ursus

11/18/2018, 1:33 AM
im using sealed classes because some of the states need payload, that is just a excrept
well, it need to refuse next MuteMic actionin case of multithreading / async (while still pending) , but more importantly UI needs to reflect that too (grayed out,. etc)
what do you mean the next action? im not sure, you mean like say another action DisableCamera, wether its independant on the mic muting, while DisableCamera is also legal in Activated state? (but would now get refused if in ActivatedMuteMicPending state, right?)
so what would you do? have nested state machine per action that needs that pending state, yet all inside Confirmed state?
(I do for sure need a FSM, since the api is very stateful, im only having trouble with this sort of actions that are only allowed in certain states, they are not really a state transitions, but still need handling to prevent double clicks etc, so it made sense for me to route them through the state machine
t

Timmy

11/18/2018, 5:21 PM
I don't have too much experience with state machines, so take everything I say with a huge grain of salt. Yes, your DisableCamera scenario is exactly what I meant. I have tried to code an example using nested separate state machines (see https://tinyurl.com/y8uqlcag). That code is definitely not ideal, but I feel like a combined top level solution (
ActivatedMuteMicPending
) would not reduce the complexity (all these combinations of action and state would still exist) and actually increase the complexity. You might be able to write an abstraction on these pending state transitions, if you have the same pattern multiple times. The biggest takeaway from this example code for me however was the fact that it feels wrong to have asynchronous state transitions. They introduce so many gotchas (e.g. my example code has shared mutable access to
state
). A more asynchronous friendly approach would be to use actors (another topic that I'm not really that well versed in). Have a look at conflated channels to see if they can help you.
u

ursus

11/19/2018, 3:24 AM
why do you feel async transitions are wrong, only think I dont like about the sample is that you are doing them inside the SM, if you would call some lambda with effect enum argument, or return a effect, etc,,
btw I think you need to destroy the mic sm if you move from main activated to deactivated
I feel like this is precisely a concurent state machine, i.e. the usual ui toolbar selection example, isnt it?

https://youtu.be/VU1NKX6Qkxc?t=1305

t

Timmy

11/19/2018, 11:31 AM
Maybe I just think they are wrong because I have never encountered them. "Normal" state machines go from one state to another state directly when faced with an action. The pending state however does a transition without needing another action. That's the part I am uncomfortable with. Returning the effect sounds interesting, but then who is in charge of this effect? The caller? I'm not quite sure how that would look like. I agree that the mic SM needs to be destroyed or at least reset. In the video you linked it looks like the actions are synchronous yet independent. So I can click "Bold" and the SM for boldness toggles immediately. It does help you with composing the different functionalities and a degree of concurrency, i.e. the different SMs can be transitioned concurrently, but it does not address the issue of concurrency within a single SM. That is, if you want to cancel the muting (correct me if that is not a goal) you need concurrency in a single SM.
u

ursus

11/19/2018, 3:17 PM
If you wanna be super clean you do Action.MuteMic .. and then Action.MuteMicCompleted which transitions from oending to final
im not sure about the concurency, i think its fine, youd need a queue anyways I think, or atleast a synchronization? And if they are unrelated then its a separate SM, which thrn should not block
Im just wondering how to implement all this, usually people have State object that contains the process() method, but then youd emit this State object, with such method? feels weird