psibr / REstate

Portable state-flows (state-machine based workflows)
MIT License
36 stars 7 forks source link

Natural StateMachines cannot transition on interfaces #60

Open aidapsibr opened 5 years ago

aidapsibr commented 5 years ago

When defining a transition between two states in a natural schematic, using an interface appears to work, but at run-time it will never resolve to a valid transition.

REstate Package Versions

9.0.0-preview10

Steps to Reproduce

  1. Add a transition with a interface signal
  2. Send a concrete object casted as that interface
  3. Fails

Expected behavior: Transition succeeds.

Actual behavior: Transition not defined exception is thrown.

Reproduces how often: 100%

aidapsibr commented 5 years ago

This is probably not ever going to be supported as it leaves too many open paths on the schematic.

One of the possible ways to address this is to add a generic constraint: where TSignal : class, this would at least make it clear it cannot be an interface. Regarding base classes (and abstract), there aren't really many options here that don't hinder other use cases (such as a new() constraint). I'd just add it as a documentation candidate on the builder method and stop there.

aidapsibr commented 4 years ago

Revisiting this, it still sucks. where TSignal : class wont work since that just means is a reference type. I'm getting really close to saying it should be where TSignal : new() to prevent the kinds of major confusion that can happen when you think an action will be invoked, but at run-time it doesn't resolve...

The other solution is to do some run-time checking on the State to see if multiple actions are implemented, INaturalAction<TSignal> or INaturalPrecondition<TSignal> doesn't match the TSignal in INaturalState<TSignal>.

The run-time checking would be useful in either case since base classes can still be an issue here.

aidapsibr commented 4 years ago

This is the desired behavior, but there is some inflexibility in limiting what objects can be signals.

image

aidapsibr commented 4 years ago

@zoeysaurusrex and I tackled this together last night and have a solution that solves about 1/2 of the problems. In the new pattern, you can multiple Actions/Preconditions on states (Yay!!) and it works!. The only issue is one of those could be an interface, if you for instance implement IAcceptSignal<IProvisionedSignal> and IAcceptSignal<ReserveSignal> where ReserveSignal implements IProvisionedSignal, then which action/precondition would execute?.