final class · System.Reactive
Effect
public final class Effect
A computation that runs again whenever a Source it read notifies, until disposed.
- Kind
- final class
- Namespace
- System.Reactive
- Assembly
- System.Core
- Access
- public, final
- Source file
Reactive.ant
Inheritance
- Base classes
-
AnyEffect
Constructors
new(func body)
#
Properties
Methods
Run()
#
Runs the computation, tracking what it reads (not while it already runs, nor once disposed). It starts from no dependencies: only what this run reads keeps running it.
Trigger()
#
What a change does to it: runs it, or (lazy) marks it stale once and notifies what depends on it.
Dispose()
#
Stops it: it never runs again, and no Source keeps it.
Private and internal members (16)
func body
#
For each source, its slot in that source's observers.
The ids of sources once there are more than a few (below that a search of the list is quicker).
Where it is in the batch's pending effects (while Pending).
How many times it let go of its sources: a Source's mark of one of its runs holds until then.
A lazy effect (a Computed's) does not run when notified: it goes stale, and tells Dependents.
Whether this run read source already.
source keeps it in slot: where the source is in its list.
The source at back moved it to slot.
Release()
#
Inherited members (5)
GetTypemethod from AnyUndescribedmethod from AnyToStringmethod from AnyHashmethod from Anydestroymethod from Any
Source
Effect as Antril, decompiled from its Larva HIR.
// System.Reactive.Effect — System.Core (decompiled from Larva HIR)
import System;
into namespace System.Reactive
{
/// A computation that runs again whenever a Source it read notifies, until disposed.
public final class Effect
{
func body;
bool running;
bool disposed;
List<Source> sources;
/// For each source, its slot in that source's observers.
List<i32> slots;
/// The ids of `sources` once there are more than a few (below that a search of the list is quicker).
HashSet<i64>? ids;
Release()
{
loop (i32 i = 0..sources.Count)
sources[i].Unlink(slots[i]);
sources.Clear();
slots.Clear();
ids = null;
Runs++;
}
internal:
bool Pending;
/// Where it is in the batch's pending effects (while Pending).
i32 PendingAt;
/// How many times it let go of its sources: a Source's mark of one of its runs holds until then.
i64 Runs;
/// A lazy effect (a Computed's) does not run when notified: it goes stale, and tells `Dependents`.
bool Lazy;
bool Stale;
Source? Dependents;
/// Whether this run read `source` already.
Reads(Source source) : bool
{
if (ids is HashSet<i64> known)
return known.Contains(source.Id);
loop (i32 i = 0..sources.Count)
{
if (sources[i] == source)
return true;
}
return false;
}
/// `source` keeps it in `slot`: where the source is in its list.
Watching(Source source, i32 slot) : i32
{
sources.Add(source);
slots.Add(slot);
if (ids is HashSet<i64> known)
known.Add(source.Id);
else if (sources.Count > 8)
{
HashSet<i64> all = new HashSet<i64>();
loop (i32 i = 0..sources.Count)
all.Add(sources[i].Id);
ids = all;
}
return sources.Count - 1;
}
/// The source at `back` moved it to `slot`.
Moved(i32 back, i32 slot)
{
slots[back] = slot;
}
public:
new(func body)
{
sources = new List<Source>();
slots = new List<i32>();
this.body = body;
}
/// Runs the computation, tracking what it reads (not while it already runs, nor once disposed). It starts
/// from no dependencies: only what this run reads keeps running it.
Run()
{
if (running || disposed)
return;
running = true;
Release();
Effect? previous = Reactive.Current;
Reactive.Current = this;
try
{
body();
}
finally
{
Reactive.Current = previous;
running = false;
Stale = false;
}
}
/// What a change does to it: runs it, or (lazy) marks it stale once and notifies what depends on it.
Trigger()
{
if (!Lazy)
{
Run();
return;
}
if (Stale || disposed)
return;
Stale = true;
if (Dependents is Source dependents)
dependents.Notify();
}
/// Stops it: it never runs again, and no Source keeps it.
Dispose()
{
disposed = true;
Release();
}
/// How many sources its last run read.
i32 Sources
{
get => sources.Count;
}
bool Disposed
{
get => disposed;
}
}
}