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

multiple edges with same origin/destination should be possible under different actions #325

Open
StoneCypher opened this issue Jan 20, 2020 · 1 comment

Comments

@StoneCypher
Copy link
Owner

honestly i thought they already were but apparently not

a 'foo' -> c;
a 'bar' -> c;

no bueno. target throws "already has."

the general case of the single edge restriction is positive, as it prevents errors. this however is clearly negative: two different actions should be able to result in the same state.

by example consider that a troll machine, an orc machine, and a goblin machine should behave differently to attack by greater (troll fight, orc flee, goblin flee) or lesser (troll fight, orc fight, goblin flee

As a result, the appropriate orc machine will work:

attacked 'attacker_is_lesser'  -> fight_back;
attacked 'attacker_is_greater' -> flee;

But the appropriate troll machine will collide:

attacked 'attacker_is_lesser'  -> fight_back;
attacked 'attacker_is_greater' -> fight_back;

And so will the appropriate goblin machine:

attacked 'attacker_is_lesser'  -> flee;
attacked 'attacker_is_greater' -> flee;

This is not desirable and should be fixed.

Discovered when @machinshin was using actions to tag a bunch of things H2 on this

@xtovski
Copy link

xtovski commented Jul 15, 2022

The reason I'm dragging my heels is that a huge portion of the codebase is written with the assumption that you can ask the machine for the edge between a and b, and get an unambiguous answer

To do this would break that, which is a massive breaking change and also would mean a whole bunch of stuff would need to move to being container based, which would probably slow things down by an order of ten

I have kicked around the idea of saying "it'll return the main path and only main path has this restriction" but that still breaks older machines written without main paths

I'm still thinking over what I think is the right thing to do here

From how I see JSSM now I would propose two things:

  1. Having several edges (actions) that define transition between same states.It makes even more sense if we emphasize on using "=>" as a form to explicitly define the only default/main transition path. Once there is no main path and multiple "->" transitions are present to the same states, the one with no action specified becomes main, and if such transition can not be found then we return exception on whatever process tries to determine main transition path, or, if we consider throwing an exception to be very extreme, we could just return false for whatever method that is depending on determining default path. It will create ambiguity in terms of default path determination, and we are moving this use-case into responsibility area of a state machine designer, but we are also removing a lot of unnecessary clutter in state machine processing (like I am doing with state machine factory now).
  2. Provide a method (lets say default_transition) to perform transition using default/main path according to state machine definition. For example, the state machine defined as
a 'do-this' => b;
a 'do-that' -> b;

would be used like this:

sm.state(); // a
sm.default_transition('a'); // {action: 'do-this', result: true}
sm.state(); // b

That would be enough to determine if transition happened (by verifying the result) and what action took place (value of action).

PS. I also think that returning simple boolean for sm.default_transition('a'); would also be quite sufficient, but in this case I would prefer to have some ability to assign hooks for an action being used during default transition so I would be able to do something that depends on that action.

And speaking of breaking change, you are 100% correct. We all dislike breaking changes. Having said that I think you may also consider moving forward, maybe introduce some distinction between state machine definition versions. Again, performance is not the strongest side of V8 used in modern browsers and NodeJS, compared with C/C++, or even Golang.

I'm happy to have JSSM as a state manager for ReactJS frontends and ReactNative apps (as a NodeJS-based MVP microservice) as it solves a lot of problems with state management that these frameworks inherently have and now I can change UI navigation behavior simply by changing state machine definition which can be even dynamically loaded from the back-end.
So thank you for your efforts.

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