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

[v5] Interpret all behaviors #3455

Merged
merged 217 commits into from
Jan 3, 2023
Merged

[v5] Interpret all behaviors #3455

merged 217 commits into from
Jan 3, 2023

Conversation

davidkpiano
Copy link
Member

@davidkpiano davidkpiano commented Jul 13, 2022

The biggest changes:

  • ObservableActorRef is removed
  • interpret now works with any Behavior: interpret(behavior)
  • The Behavior interface now has Behavior.getSnapshot, which is important for determining which "state" should be exposed, and which state is internal state
  • predictableActionArguments flag is removed; actorCtx.exec is used instead
  • Most state-machine-specific code is removed from the Interpreter; still have some more work to do here

@changeset-bot
Copy link

changeset-bot bot commented Jul 13, 2022

🦋 Changeset detected

Latest commit: fc3ca72

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
xstate Major
@xstate/fsm Major
@xstate/react Major
@xstate/vue Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jul 13, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit fc3ca72:

Sandbox Source
XState Example Template Configuration
XState React Template Configuration

@ghost
Copy link

ghost commented Jul 13, 2022

👇 Click on the image for a new way to code review
  • Make big changes easier — review code in small groups of related files

  • Know where to start — see the whole change at a glance

  • Take a code tour — explore the change with an interactive tour

  • Make comments and review — all fully sync’ed with github

    Try it now!

Review these changes using an interactive CodeSee Map

Legend

CodeSee Map Legend

@davidkpiano
Copy link
Member Author

davidkpiano commented Aug 7, 2022

@Andarist There are 2 tests in @xstate/react only failing; can you help me investigate those? EDIT: resolved

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Comment on lines +401 to +405
public getStatus(state: State<TContext, TEvent, TResolvedTypesMeta>) {
return state.done
? { status: 'done', data: state.output }
: { status: 'active' };
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need an extra error status for cases when something throws an error and we "forcefully" stop the machine (and notify subscribers about the error)

@@ -2,30 +2,18 @@ import type {
InvokeCallback,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is in the actors.ts but we refer to them as behaviors. It feels like we should do something about it because it feels like we are getting lost ourselves in the used nomenclature

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this in a separate PR (want to rename to behaviors.ts because it's a noisy change

@Andarist
Copy link
Member

  1. I feel that it's crucial for this PR to make StateMachine implement the Behavior interface. As long as it doesn't implement it, it feel like interpret isn't actually accepting Behavior - it's accepting Behavior | StateMachine, and thus the unification process of all the things didn't actually succeed. I have a comment that goes into this a little bit further here
  2. with interpret accepting any Behavior we end up with some problems in @xstate/react etc. Its useInterpret has some very machine-oriented options (and it's still accepting TMachine and not TBehavior). That probably can be handled in a separate PR but it's worth noting here.
  3. There is one minor unanswered comment here
  4. Behavior['getInitialState'] is calling factories embedded in behaviors and those are usually side-effectful. This is a big problem because those functions should not be called before Interpreter['start']. I think that this code should be moved to Behavior['start'] (which is a method declared in the type but in practice it's not implemented by anything) and that Behavior['getInitialState'] has to be made pure. Accompanying tests should be introduced to make sure that we don't call side-effects within getInitialState (or within interpret(behavior).getSnapshot() as that's a more public-facing API and it's something that might lead to calling behavior.getInitialState). I've mentioned this here
  5. Interpreter has two different defer methods (yes, one is on the ActorContext but that doesn't quite make it less confusing especially when both are used within some exec-related code), the first one and the second one. I think that it's best to rename one of them and that possibly it's easier to rename the second one.
  6. I think that observer.done has been shoehorned on the existing concept that doesn't support this. If we have to do that, it raises the question if we are using this concept correctly. I think that it would be best to avoid such custom extensions if we plan to use to the concepts of observers, observables etc. No observable-specific code will actually be able to utilize this custom extension in a generic way and it's a bad thing. One of the main places in which Observer['done'] is being used is when the child actor gets started - we then subscribe to it (in the parent) and listen for its done callback to send the done.invoke.* even to ourselves. This is conceptually a little bit weird because the responsibility to send that event has been moved to the parent whereas the more straightforward way of doing that would be to send that even directly from the child to the parent. We don't need to use a separate "channel" for communication like this as we already have our own, standard, channel that we can use for communication. I managed to remove this in this PR. The only downside there is that onDone's implementation is a little bit funky - but that's perhaps easily solvable by just changing the callback's argument: it could be TOutput (once we add it) instead of DoneEvent. This would match what you have noted as a desired semantic for done here

@davidkpiano
Copy link
Member Author

davidkpiano commented Dec 28, 2022

@Andarist

  1. Agree re: making StateMachine implement a Behavior interface. Will look into this soon. Done in 39104d6
  2. Discussed in Discord; we'll handle this in a separate PR with the goal of useMachine -> useBehavior and useInterpret working with any Behavior.
  3. See reply - unsure what to test there.
  4. This is resolved and all tests passing in [v5] Refactor actions #3726 ✅ The last thing to fix there is invoke(...) types.
  5. Will rename one of the defers, and eventually figure out a better way to handle "deferred" actions (not really deferred, just moved to the end of the queue) Renamed in 951847a
  6. Your PR Remove a custom done callback from the Observer #3720 has been merged for this 👍

We're getting close!

davidkpiano and others added 6 commits January 2, 2023 08:41
* Simplify function signature of `interpreter.send(eventObj)`

* Remove unused types

* Add changeset

* Cleanup types

* Simplify more event-related methods and functions (#3570)

* Add changeset for `@xstate/fsm`

* Fix tests

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
* Test cleanup

* Committing this just to checkpoint it

* Add status, change Actorcontext.exec sig

* Actions resolve to tuple

* Declassify ExeuctableAction

* Goodbye ExecutableAction

* Goodbye exec.ts

* Refactor createDynamicAction

* More refactoring

* Yay more deleting

* More refactoring

* exectute2 -> execute

* Enable root initial actions (addresses #466)

* Working through types

* Still working on types

* Sorry, getting a little messy again

* Revert "Sorry, getting a little messy again"

This reverts commit a609de8.

* Fix test

* Ensure no side-effects in getInitialState

* I guess this makes sense

* Started state should come from behavior.start if it exists

* Get rid of state-specific stuff

* Remove test

* Update packages/core/test/predictableExec.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Refactor test

* Update packages/core/test/actions.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Update packages/core/test/actions.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Update packages/core/test/predictableExec.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Remove unused import

* Update packages/core/test/actions.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Update packages/core/test/actions.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Interpreter tests

* Remove unused `ActorContext['exec']` (#3734)

* Fixed initial state cache eviction in the `Interpreter` (#3733)

* Tweak logic around stopping actors (#3737)

* Tweak logic around stopping actors

* remove unused imports

* Reuse the `ActorStatus` enum in the `handleAction`

* Tweak types

* Free the stopped `sessionId` in the registry

* Make `getInitialState` in the `Interpreter` private (#3738)

* Update packages/core/test/interpreter.test.ts

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>

* Update packages/core/src/stateUtils.ts

* Small cleanup of internal implementations of actors (#3740)

* Small cleanup of internal implementations of actors

* Remove redundant completion notifications sent out by some actors

* Wrap sending `xstate.snapshot.${id}` events with `defer`

* Drop the unused "next" case from the event observable

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
@davidkpiano davidkpiano merged commit ec39214 into next Jan 3, 2023
@davidkpiano davidkpiano deleted the v5/interpret-all-behaviors branch January 3, 2023 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants