Effect class sealed

A declarative lifecycle-bound side-effect node that executes an untracked action upon upstream mutations.

Under the two-plane reactive architecture of the Bloom framework:

  • Data Plane (Bloom): Evaluates and propagates state mutations downstream via the 2-Phase Push-Dirty / Lazy-Pull DAG.
  • Lifecycle Plane (Tether): Declarative lifecycle entities governed by enclosing tracking scopes via BloomVia.tether or executed imperatively via EffectRunner.
  • An Effect encapsulates an internal terminal (_Terminal) that acts as a non-propagating terminal sink (_isNewerThan always returns false), executing pure side-effects (analytics, external I/O sync, storage, audio/haptic feedback) without mutating intermediate DAG nodes or propagating dirty pulses downstream.

Sub-Factory Pathways

Effect(...)                 ──> Manifest N-ary effect ([Effect])
  ├─ .unary(...)            ──> Fast-path unary manifest effect
  ├─ .via(...)              ──> Dynamic discovery effect
  ├─ .scoped(...)           ──> Scoped effect with lifecycle context ([EffectScope])
  │    ├─ .unary(...)       ──> Scoped unary effect
  │    └─ .via(...)         ──> Scoped dynamic discovery effect
  ├─ .debounce(...)         ──> Time-stabilized debounce effect
  │    └─ .unary(...)       ──> Unary debounce effect
  ├─ .throttle(...)         ──> Rate-limited throttle effect
  │    └─ .unary(...)       ──> Unary throttle effect
  └─ .group(...)            ──> Composite effect group

System Architectural Flow

                    Upstream Bloom Invalidation
                                │
                                ▼ (Push-Dirty Notification)
                   ┌─────────────────────────┐
                   │    Schedule Terminal    │ (_Scheduler.instance._scheduleTerminal)
                   └────────────┬────────────┘
                                │ (Scheduled Turn Execution)
                                ▼
                   ┌─────────────────────────┐
                   │     _resolveDirty()?    │ (2-Phase Verification)
                   └────────────┬────────────┘
                                │
                 ┌──────────────┴──────────────┐
          (false)│                             │(true)
                 ▼                             ▼
          [Abort execution]           ┌────────────────┐
        (No actual mutation)          │ Check guard()? │
                                      └────────┬───────┘
                                               │
                                ┌──────────────┴──────────────┐
                         (false)│                             │(true / no guard)
                                ▼                             ▼
                         [Skip execution]             [Consume 1 take Ticket]
                         [Retain tickets]                     │
                                                              ▼
                                                 [Execute action() Untracked]
                                                              │
                                                 ┌────────────┴────────────┐
                                                 │ Exhausted take tickets? │
                                                 └────────────┬────────────┘
                                                              │(true)
                                                              ▼
                                                     [Auto-Deactivate]
                                                     [Early Teardown]

Key Invariants & Architectural Benefits

  1. Zero-Glitch Terminal Sinks: Effects fire only after state transactions settle via the Bloom microtask scheduler, eliminating transient tearing and intermediate glitch states.
  2. Precondition Gating with Ticket Preservation: When guard returns false, execution is aborted without consuming take tickets.
  3. Sound Early Teardown: An effect configured with take automatically deactivates and detaches its subscription edges once the ticket quota reaches zero.
  4. Unified Creation Pathways: Instances are constructed exclusively via the Effect factories and sub-factories (Effect(...), Effect.unary(...), Effect.via(...), Effect.scoped(...), Effect.debounce(...), Effect.throttle(...), Effect.group(...)).
  5. Declarative Lifecycle Management: Tethering via via.tether() automatically aligns effect lifecycles with the enclosing computation scope.

Warning (Anti-Pattern Prevention):

  • Do NOT mutate observed targets synchronously inside action without an exit condition, as it induces reentrant invalidation loops.
  • Do NOT instantiate new Effect objects inside build methods without caching or lifecycle tethering.

BAD:

// [Anti-Pattern] Synchronously mutating target inside its own effect without an exit condition
final counter = blooming(0);
Effect([counter.bloom], () {
  counter.set(untracked(counter.bloom) + 1); // Triggers infinite invalidation loop!
});

GOOD:

// [Recommended] One-way terminal sink for external interactions
final counter = blooming(0);
Effect([counter.bloom], () {
  analyticsService.logCounter(untracked(counter.bloom)); // Pure side-effect sink
});

Examples

final user = blooming('Alice');
final auth = blooming(true);

final syncEffect = Effect(
  [user.bloom, auth.bloom],
  () => syncSession(untracked(user.bloom), untracked(auth.bloom)),
  take: 5,
);
Inheritance
Implemented types
Available extensions

Constructors

Effect(Iterable<Bloom> targets, void action(), {bool guard()?, int? take, void onUncaughtError(Object error, StackTrace stackTrace)?})
Creates a manifest Effect attached strictly to explicit targets.
factory
Effect.group(Iterable<Effect> effects)
Bundles a collection of effects into a composite Effect managing their aggregated lifecycle.
factory
Effect.unary(Bloom target, void action(), {bool guard()?, int? take, void onUncaughtError(Object error, StackTrace stackTrace)?})
Creates an optimized unary manifest Effect attached strictly to a single explicit target.
factory
Effect.via(void action(BloomVia via), {bool guard(BloomVia via)?, void onUncaughtError(Object error, StackTrace stackTrace)?})
Creates an explicit dynamic discovery Effect using BloomVia.
factory

Properties

debugCreationLocation → String?

Available on T, provided by the TetherDebugExtension extension

The exact code location where this tether was instantiated in debug mode.
no setter
debugDependencies → List<BloomDebugSnapshot>

Available on Effect, provided by the EffectDebugExtension extension

Debug-only list of active upstream dependencies currently monitored by this effect's terminal.
no setter
debugLabel ↔ String?

Available on T, provided by the TetherDebugExtension extension

A developer-defined label to identify this tether in debug mode.
getter/setter pair
hashCode → int
The hash code for this object.
no setterinherited
isActive → bool
Whether the node is currently active (connected to a downstream terminal).
no setterinherited
runner → EffectRunner

Available on Effect, provided by the EffectStartExtension extension

Creates a dormant, unstarted EffectRunner for this effect.
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited

Methods

debugTrace([String? label, int traceCount = 5]) → void

Available on T, provided by the TetherDebugExtension extension

Captures the current stack trace and assigns an optional label to this tether.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
start() → EffectRunner

Available on Effect, provided by the EffectStartExtension extension

Instantiates an EffectRunner and immediately starts observation and execution.
toString() → String
A string representation of this object.
inherited
withDebugLabel(String label) → T

Available on T, provided by the TetherDebugExtension extension

Assigns a developer-defined debug label and returns this tether.

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

debounce → const EffectDebounceFunctor
Sub-factory providing time-domain debounce rate-limiting.
scoped → const EffectScopedFunctor
Sub-factory providing managed lifecycle EffectScope callbacks with cleanup registration.
throttle → const EffectThrottleFunctor
Sub-factory providing time-domain throttle rate-limiting.