Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

suggestion about state and context #23

Open
bootchk opened this issue May 1, 2015 · 4 comments
Open

suggestion about state and context #23

bootchk opened this issue May 1, 2015 · 4 comments

Comments

@bootchk
Copy link

bootchk commented May 1, 2015

Suggestions and comments about the design (not a bug.)

Should state be an attribute of the machine, or the object which is going through the machine?

My use case is a game having many tokens (AKA sprites) each having state and a state machine. I don't mind each token owning an instance of StateMachine, but then I must configure each instance the same way (easy enough to workaround.) But possibly a StateMachine should have a Design which is configured and passed to a StateMachine instance.

In other implementations of FSM 'context' seems to mean: the object which has state, which the state machine sets the state of, and which is passed to all actions (what you call Handlers) for them to act on. Your context is not the same thing? Maybe a solution is a delegate for the state machine?

On another topic, I don't understand the use case for AnyState. Is one use case adding transitions from any state to a reset state, so that you don't have to specify a transition from every state to the reset state? Maybe you could explain in your document. But I should read the code, and for example study what a transition from AnyState to AnyState would mean.

Thanks, SwiftState is rather elegant.

@inamiy
Copy link
Member

inamiy commented May 3, 2015

Hi, thanks for great feedback :)

My use case is a game having many tokens (AKA sprites) each having state and a state machine. I don't mind each token owning an instance of StateMachine, but then I must configure each instance the same way (easy enough to workaround.) But possibly a StateMachine should have a Design which is configured and passed to a StateMachine instance.

Design sounds a good idea.
I was also thinking about Graphviz (DOT file) support in #4,
so using (Route)Design class will help its printing and also an easy configuration to StateMachine.

In other implementations of FSM 'context' seems to mean: the object which has state, which the state machine sets the state of, and which is passed to all actions (what you call Handlers) for them to act on. Your context is not the same thing? Maybe a solution is a delegate for the state machine?

I guess that is Event in SwiftState's terminology.

By the way, SwiftState's HandlerContext is just a Handler's tuple argument.
I used this term similar to UIViewController Transitioning API, where view transition invokes methods with passing transitionContext argument.

On another topic, I don't understand the use case for AnyState. Is one use case adding transitions from any state to a reset state, so that you don't have to specify a transition from every state to the reset state? Maybe you could explain in your document. But I should read the code, and for example study what a transition from AnyState to AnyState would mean.

Exactly right. What you mentioned is one of good ways of using AnyState.
You can also combine with condition as a blacklist to define the route, e.g. StateMachineTests.swift#L116-L129

@bootchk
Copy link
Author

bootchk commented May 3, 2015

More discussion about context, delegate, handlers....

In your tests, you pass an unnamed closure as a Handler. The closure is bound to variables in scope, for example to "var returnedTransition: StateTransition?". What I think I need is passing a named closure as a Handler, where the named closure is a method bound at runtime in the statemachine to some delegate object instance.

For exaple:

delegate1 = SKLabelNode()
delegate2 = SKLabelNode()

design = StateMachineDesign()
// setScale is a method of SKNode which is superclass of SKLabelNode
design.addRoute(.State0 => .State1, event: .Event0, handler: setScale(50) )

delegate1.sm = StateMachine(design: design, delegate: delegate1)
delegate2.sm = StateMachine(design: design, delegate: delegate2)

delegate1.sm <-! .Event0

Then the stateMachine changes the state of delegate1 and calls method setScale bound to delegate1. I.E. this pseudocode inside StateMachine:

self.delegate.handler()

I hope that gives the idea, but I’m still thinking, I haven't tested. Possibly SwiftState already allows that.

@inamiy
Copy link
Member

inamiy commented May 3, 2015

Though there's no direct support of delegation in current SwiftState, I think you can do the similar thing just by wrapping with closure of Handler type (will be a bit lengthy):

// NOTE: HandlerContext is omitted using `_`
machine.addRouteEvent(.Event0, transitions: [.State0 => .State1], handler: { [weak delegate] _ in delegate?.setScale(50) })

If we are going to support for a better delegation syntax as you mentioned above, however, there will be many difficulties because Swift itself doesn't support runtime messaging (needs Foundation.framework). In your example, if setScale(50) is called without delegate. prefix, it will just prompt compile error.

So, here's one alternative solution I came up with...

  1. [User side] Create free (global) func setScale() instead of delegate-bounded instance method. It's signature must be of the curried form func setScale(scale: Float, ...)(delegate: StateMachineDelegateProtocol) or func setScale(sclae: Float, ...) -> (StateMachineDelegateProtocol -> Void).
  2. [Library side] Support above free function event handler.

But (1) seems too heavy a burden for users, so I'm currently thinking of (2) not necessary for a while.

@bootchk
Copy link
Author

bootchk commented May 12, 2015

Thanks. That all seems correct. Because Swift does not support runtime messaging, I think I will NOT attempt to use a design, but just implement a StateMachine factory that binds an instance of what would be a delegate to a instance of StateMachine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants