Skip to content

Commit

Permalink
Lazy evaluation / hybrid push-pull execution model (#323)
Browse files Browse the repository at this point in the history
Co-authored-by: rdot117 <[email protected]>
Co-authored-by: funwolf7 <[email protected]>
  • Loading branch information
3 people authored Aug 16, 2024
1 parent b2999f9 commit e690edc
Show file tree
Hide file tree
Showing 86 changed files with 4,368 additions and 2,152 deletions.
8 changes: 8 additions & 0 deletions .vscode/Fusion.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": ".."
}
],
"settings": {}
}
5 changes: 1 addition & 4 deletions docs/api-reference/animation/types/spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</h1>

```Lua
export type Spring<T> = StateObject<T> & Dependent & {
export type Spring<T> = StateObject<T> & {
kind: "Spring",
setPosition: (self, newPosition: T) -> (),
setVelocity: (self, newVelocity: T) -> (),
Expand All @@ -21,9 +21,6 @@ export type Spring<T> = StateObject<T> & Dependent & {
A specialised [state object](../stateobject) for following a goal state smoothly
over time, using physics to shape the motion.

In addition to the standard state object interfaces, this object is a
[dependent](../dependent) so it can receive updates from the goal state.

The methods on this type allow for direct control over the position and velocity
of the motion. Other than that, this type is of limited utility outside of
Fusion itself.
Expand Down
5 changes: 1 addition & 4 deletions docs/api-reference/animation/types/tween.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@
</h1>

```Lua
export type Tween<T> = StateObject<T> & Dependent & {
export type Tween<T> = StateObject<T> & {
kind: "Tween"
}
```

A specialised [state object](../stateobject) for following a goal state smoothly
over time, using a `TweenInfo` to shape the motion.

In addition to the standard state object interfaces, this object is a
[dependent](../dependent) so it can receive updates from the goal state.

This type isn't generally useful outside of Fusion itself.

-----
Expand Down
92 changes: 89 additions & 3 deletions docs/api-reference/general/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,27 @@ You attempted to create a type of instance that Fusion can't create.

<div class="fusiondoc-error-api-section" markdown>

## cannotDepend

```
Observer can't depend on Observer.
```

**Thrown by:**
[`Observer`](../../graph/members/observer)

You attempted to form a dependency between two
[graph objects](../../graph/types/graphobject), but either the dependency set or
dependent set were frozen.

You might be trying to connect them in the wrong order, or the objects might not
be designed to have dependents or dependencies.
</div>

-----

<div class="fusiondoc-error-api-section" markdown>

## cleanupWasRenamed

```
Expand Down Expand Up @@ -492,12 +513,33 @@ Roblox's task scheduling APIs.

<div class="fusiondoc-error-api-section" markdown>

## poisonedScope

```
Attempted to use a scope after it's been destroyed; `doCleanup()` was previously
called on this scope. Ensure you are not reusing scopes after cleanup.
```

**Thrown by:**
scopes after being passed to [`doCleanup`](../../memory/members/doCleanup)

If you attempt to read from, or write to, a scope that's been destroyed, this
message is shown. After a scope has been cleaned up, your code should forget the
reference to it, as it is no longer valid.

</div>

-----

<div class="fusiondoc-error-api-section" markdown>

## possiblyOutlives

```
The Value object could be destroyed before the Computed that is use()-ing it;
review the order they're created in, and what scopes they belong to. See
discussion #292 on GitHub for advice.
The Computed (bound to the PaddingLeft property) will be destroyed before the
UIPadding instance; the latter is in a different scope that gets destroyed too
quickly. To fix this, review the order they're created in, and what scopes they
belong to. See discussion #292 on GitHub for advice.
```

**Thrown by:**
Expand Down Expand Up @@ -684,6 +726,50 @@ for more predictable behaviour and better support for constant values.

<div class="fusiondoc-error-api-section" markdown>

## tweenNanGoal

```
A tween was given a NaN goal, so some animation has been skipped. Ensure no
tweens have NaN goals.
```

**Thrown by:**
[`Tween`](../../animation/members/tween)

The goal parameter given to the tween during construction contained one or more
NaN values.

This typically occurs when zero is accidentally divided by zero, or some other
invalid mathematical operation has occurred. Check that your code is free of
maths errors, and handles all edge cases.
</div>

-----

<div class="fusiondoc-error-api-section" markdown>

## tweenNanMotion

```
A tween encountered NaN during motion, so has snapped to the goal. Ensure no
tweens have NaN in their tween infos.
```

**Thrown by:**
[`Tween`](../../animation/members/tween)

While calculating an updated tween position, the final value contained one or
more NaN values.

This typically occurs when zero is accidentally divided by zero, or some other
invalid mathematical operation has occurred. Check that your code is free of
maths errors, and handles all edge cases.
</div>

-----

<div class="fusiondoc-error-api-section" markdown>

## unknownMessage

```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<nav class="fusiondoc-api-breadcrumbs">
<span>State</span>
<span>Graph</span>
<span>Members</span>
<span>Observer</span>
</nav>
Expand Down Expand Up @@ -50,8 +50,8 @@ destruction tasks for this object.

The target that the observer should watch for changes.

!!! note "Works best with state objects"
While non-[state object](../../../state/types/stateobject) values are
!!! note "Works best with graph objects"
While non-[graph object](../../types/graphobject) values are
accepted for compatibility, they won't be able to trigger updates.

-----
Expand Down
126 changes: 126 additions & 0 deletions docs/api-reference/graph/types/graphobject.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<nav class="fusiondoc-api-breadcrumbs">
<span>Graph</span>
<span>Types</span>
<span>GraphObject</span>
</nav>

<h1 class="fusiondoc-api-header" markdown>
<span class="fusiondoc-api-icon" markdown>:octicons-note-24:</span>
<span class="fusiondoc-api-name">GraphObject</span>
</h1>

```Lua
export type GraphObject = ScopedObject & {
createdAt: number
dependencySet: {[GraphObject]: unknown},
dependentSet: {[GraphObject]: unknown},
lastChange: number?,
timeliness: "lazy" | "eager",
validity: "valid" | "invalid" | "busy",
_evaluate: (GraphObject, lastChange: number?) -> boolean
}
```

A reactive graph object which can broadcast and receive updates among other
members of the reactive graph.

This type includes [`ScopedObject`](../../../memory/types/scopedobject), which
allows the lifetime and destruction order of the reactive graph to be analysed.

!!! note "Non-standard type syntax"
The above type definition uses `self` to denote methods. At time of writing,
Luau does not interpret `self` specially.

-----

## Members

<h3 markdown>
createdAt
<span class="fusiondoc-api-type">
: number
</span>
</h3>

The `os.clock()` time of this object's construction, measured as early as
possible in the object's constructor.

<h3 markdown>
dependencySet
<span class="fusiondoc-api-type">
: {[GraphObject]: unknown}
</span>
</h3>

Everything this reactive graph object currently declares itself as dependent
upon.

<h3 markdown>
dependentSet
<span class="fusiondoc-api-type">
: {[GraphObject]: unknown}
</span>
</h3>

The reactive graph objects which declare themselves as dependent upon this
object.

<h3 markdown>
lastChange
<span class="fusiondoc-api-type">
: number?
</span>
</h3>

The `os.clock()` time of this object's most recent meaningful change, or `nil`
if the object is newly created.

<h3 markdown>
timeliness
<span class="fusiondoc-api-type">
: "lazy" | "eager"
</span>
</h3>

Describes when this object expects to be revalidated. Most objects should use
`lazy` timeliness to defer computation as late as possible. However, if it's
important for this object to respond to changes as soon as possible, for example
for the purposes of observation, then `eager` timeliness ensures that a
revalidation is dispatched as soon as possible.

<h3 markdown>
validity
<span class="fusiondoc-api-type">
: "valid" | "invalid" | "busy"
</span>
</h3>

Whether the most recent validation operation done on this graph object was a
revalidation or an invalidation. `busy` is used while the graph object is in
the middle of a revalidation.

-----

## Methods

<h3 markdown>
_evaluate
<span class="fusiondoc-api-type">
-> boolean
</span>
</h3>

```Lua
function GraphObject:_evaluate(): boolean
```

Called by Fusion while the graph object is in the process of being evaluated.
This is where logic to do with computational updates should be placed.

The return value is `true` when a 'meaningful change' occurs because of this
revalidation. A 'meaningful change' is one that would affect dependencies'
behaviour. This is used to efficiently skip over calculations for dependencies.

!!! fail "Restrictions"
This method should finish without spawning new processes, blocking the
thread, or erroring.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<nav class="fusiondoc-api-breadcrumbs">
<span>State</span>
<span>Graph</span>
<span>Types</span>
<span>Observer</span>
</nav>
Expand All @@ -10,15 +10,16 @@
</h1>

```Lua
export type Observer = Dependent & {
export type Observer = GraphObject & {
type: "Observer",
timeliness: "eager",
onChange: (self, callback: () -> ()) -> (() -> ()),
onBind: (self, callback: () -> ()) -> (() -> ())
}
```

A user-constructed [dependent](../dependent) that runs user code when its
[dependency](../dependency) is updated.
A [graph object](../graph object) that runs user code when it's updated by the
reactive graph.

!!! note "Non-standard type syntax"
The above type definition uses `self` to denote methods. At time of writing,
Expand Down
Loading

0 comments on commit e690edc

Please sign in to comment.