Bloom<T> class abstract base

The core read-only reactive state interface in the Bloom reactive DAG engine.

Under the strict Producer/Consumer Separation (Has-a) architecture:

  • Bloom represents the observation-only view of a reactive node.
  • It does NOT implement BloomState or BloomController directly on its public interface.
  • Mutation APIs (.set(), .data =, .setGuarded(), .setError(), .empty([reason])) are strictly confined to BloomController and RawBloomController.
  • Bloom NEVER implements BloomController, and underlying physical entry nodes are private to the library, preventing rogue downcasting at runtime.

Values and live states are read outside tracking scopes via the global untracked functor (untracked for values, BloomUntracked.state for live states), and explicitly tracked within derivation closures via injected BloomVia (via(node) for values, via.state(node) for live states).

System Architectural Flow

1. 3-State Finite State Machine (Observed via untracked.state)

                    ┌────────────────────────────────────────┐
                    │     Bloom<T> 3-State State Machine      │
                    └────────────────────────────────────────┘
                           │ (Bloom.empty<T>() or uninitialized)
                           ▼
                    ┌──────────────┐    Controller .set(data)     ┌──────────────┐
                    │    EMPTY     │ ───────────────────────────> │     DATA     │ (hasData == true)
                    │  (isEmpty)   │ <─────────────────────────── │  (payload:T) │
                    └──────┬───────┘   Controller .empty([reason])└──────┬───────┘
                           │                                             │
                           │ Controller .setError()        Controller    │
                           │                               .setError()   │
                           ▼                                             ▼
                    ┌────────────────────────────────────────────────────────────┐
                    │                           ERROR                            │ (hasError == true)
                    │              (payload: Object, [StackTrace])               │
                    └────────────────────────────────────────────────────────────┘

2. Explicit Dependency Registration vs. Raw Reads

[computed / Effect.via Scope]
            │ (Injected BloomVia parameter)
            ▼
     via(sourceBloom)          ──>  [Registers Source Edge in Active LPDAG & Evaluates T]
     via.state(sourceBloom)    ──>  [Registers Source Edge & Returns Live BloomState<T>]

[Outside Derivation Scope / Raw Read]
            │
     untracked(sourceBloom)    ──>  [Pure Direct Field Dereference: Returns T (Zero Overhead)]
     untracked.state(sourceBloom) ──> [Zero-Allocation Live BloomState<T> View]

Key Invariants & Architectural Benefits

  1. Zero-Overhead Raw Reads & Explicit Tracking: Reading via untracked is a pure field dereference with zero tracking overhead and no dynamic tracking stack penalty. Reactive derivations explicitly declare dependencies via the injected BloomVia parameter (via(node)).
  2. 3-State Exclusivity: A Bloom node's observed state is strictly in one of three mutually exclusive states:
  3. Sound Fail-Fast Extraction: Reading via untracked while in Empty or Error state throws BloomSnapshotExtractionException. Use untracked.state(node).dataOrNull, untracked.state(node).dataOrElse(), or native Dart 3 switch (untracked.state(node).phase) for safe total pattern matching.

Warning (Anti-Pattern Prevention):

  • Do NOT read reactive nodes untracked directly inside a computed or Effect.via scope without wrapping in via(...), as untracked intentionally bypasses dependency registration.
  • Do NOT mutate a BloomController inside a computed or effect reading that same node without a terminating condition, as this induces topological reentrancy cycles.

BAD:

// [Anti-Pattern] Reading untracked without via() bypasses dependency registration
final badComputed = computed((via) {
  return untracked(count.bloom) * 2; // count is NOT tracked!
});

GOOD:

// [Recommended] Explicitly register dependencies through via()
final goodComputed = computed((via) {
  return via(count.bloom) * 2; // Dynamically and explicitly registered in LPDAG
});

Examples

final counter = blooming(0);
final doubled = computed((via) => via(counter.bloom) * 2);

print(untracked(doubled)); // 0
counter.data = 5;
print(untracked(doubled)); // 10
Implemented types
Available extensions

Constructors

Bloom.constant(T data)
Creates a constant static leaf node holding an immutable valid data payload.
factory
Bloom.empty([Object? emptyReason])
Creates a constant static leaf node permanently in an uninitialized (Empty) state.
factory
Bloom.error(Object error, [StackTrace? stackTrace])
Creates a constant static leaf node permanently in an Error state.
factory
Bloom.future(Future<T> future, {T initialFactory()?, T onError(Object error, [StackTrace? stackTrace])?})
Creates a reactive Bloom node from a Dart Future.
factory
Bloom.stream(Stream<T> stream, {T initialFactory()?, T onError(Object error, [StackTrace? stackTrace])?, bool? cancelOnError, bool distinct = true, bool equals(T previous, T next)?, Graceful? graceful})
Creates a reactive Bloom node from a Dart Stream.
factory

Properties

build → BloomBuildFunctor<T>

Available on Bloom<T>, provided by the BloomFlutterExtension extension

Entry point for inline single-node reactive UI build functors (BloomBuildFunctor).
no setter
debug → BloomDebug

Available on Bloom<T>, provided by the BloomDebugExtension extension

Access point for zero-overhead node inspection and diagnostics.
no setter
debugCreationLocation → String?

Available on Bloom<T>, provided by the BloomDebugExtension extension

The exact code location where this object was created in debug mode.
no setter
debugLabel ↔ String?

Available on Bloom<T>, provided by the BloomDebugExtension extension

A developer-defined label to identify this specific object in debug mode.
getter/setter pair
debugSourceCount → int

Available on Bloom<T>, provided by the BloomDebugExtension extension

The number of active upstream source edges connected to this node for verification and testing.
no setter
debugVersion → int

Available on Bloom<T>, provided by the BloomDebugExtension extension

The internal version of this Bloom for verification and debugging.
no setter
effect → UnaryBloomEffectScope

Available on Bloom, provided by the BloomEffectExtension extension

Opens a scoped namespace for declarative reactive Effect creation targeting this node.
no setter
elements → BloomIterableElements<E>

Available on Bloom<Iterable<E>>, provided by the BloomIterableElementsExtension extension

Opens a dedicated namespace for operating on the individual elements of this Iterable reactively.
no setter
elements → BloomListElements<E>

Available on Bloom<List<E>>, provided by the BloomListElementsExtension extension

Opens a dedicated namespace for operating on the individual elements of this List reactively.
no setter
elements → BloomMapElements<K, V>

Available on Bloom<Map<K, V>>, provided by the BloomMapElementsExtension extension

Opens a dedicated namespace for operating on the individual elements of this Map reactively.
no setter
elements → BloomSetElements<E>

Available on Bloom<Set<E>>, provided by the BloomSetElementsExtension extension

Opens a dedicated namespace for operating on the individual elements of this Set reactively.
no setter
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
keyed → BloomKeyedIterableElements<E>

Available on Bloom<Iterable<E>>, provided by the BloomKeyedIterableElementsExtension extension

Opens a dedicated namespace for operating on keyed elements of this Iterable reactively.
no setter
listen → BloomListenFunctor<T>

Available on Bloom<T>, provided by the BloomFlutterExtension extension

Entry point for inline zero-rebuild side-effect listener functors (BloomListenFunctor).
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited

Methods

aggregate<R>(R aggregator(Iterable<T> elements)) → Bloom<R>

Available on Bloom<Iterable<T>>, provided by the BloomIterableComputationExtension extension

Reduces multiple inbound elements into a reactive Bloom<R>.
any([bool predicate(T item)?]) → Bloom<bool>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomExtension extension

Evaluates whether at least one element in the collection satisfies predicate.
coalesced({bool leading = false, bool trailing = true}) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Coalesces multiple synchronous invalidations into a single microtask flush.
combine() → Bloom<List<T>>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomExtension extension

Unifies all member payloads into a reactive Bloom<List<T>>.
debounced(Duration duration, {bool leading = false, bool trailing = true}) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Debounces downstream invalidation pulses across quiet periods of duration.
debugTrace([String? label, int traceCount = 5]) → void

Available on Bloom<T>, provided by the BloomDebugExtension extension

Captures the current stack trace and assigns an optional label to this Bloom.
distinct([bool equals(T previous, T next)?]) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Filters out consecutive duplicate payloads using equals (or identical / operator ==).
every([bool predicate(T item)?]) → Bloom<bool>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomExtension extension

Evaluates whether every element in the collection satisfies predicate.
fold<R>(R initialValue, R combine(R accumulator, T item)) → Bloom<R>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomExtension extension

Folds the payloads of all members into a single reactive Bloom<R>.
graceful([Graceful graceful = Graceful.microtask]) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Buffers deactivation of this node with a graceful policy when downstream subscribers drop to zero.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
provide({Key? key, required Widget child}) → BloomProvider<T>

Available on Bloom<T>, provided by the BloomProvideExtension extension

Wraps child in a BloomProvider<T> providing this reactive Bloom node.
reduce(T combine(T previous, T current)) → Bloom<T>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomExtension extension

Reduces the payloads of all members into a single reactive Bloom<T>.
retained({BloomCoupler<bool>? pending}) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Creates a retained node maintaining prior valid data during pending re-evaluations (SWR).
retainedTuple() → ({Bloom<T> data, Bloom<bool> pending})

Available on Bloom<T>, provided by the BloomComputationExtension extension

Creates a retained node maintaining prior valid data during pending re-evaluations (SWR), bundled as a ({Bloom<T> data, Bloom<bool> pending}) record.
sum() → Bloom<T>

Available on Bloom<Iterable<Bloom<T>>>, provided by the BloomIterableBloomNumericExtension extension

Aggregates all numbers in the collection into their mathematical sum as a reactive Bloom<T>.
throttled(Duration duration, {bool leading = true, bool trailing = true}) → Bloom<T>

Available on Bloom<T>, provided by the BloomComputationExtension extension

Throttles downstream invalidation pulses to at most once per duration.
toListenable({bool sync = true}) → ValueListenable<T>

Available on Bloom<T>, provided by the BloomListenableExtension extension

Converts this Bloom into a standard Flutter ValueListenable.
toString() → String
A string representation of this object.
inherited
withDebugLabel<W extends Bloom<T>>(String label) → W

Available on Bloom<T>, provided by the BloomDebugExtension extension

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

Operators

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

Static Properties

constantNull → Bloom<Null>
A canonical, immutable static leaf node permanently holding a null payload.
final

Constants

computed → const ComputedFunctor
Static entrypoint to the computed functor for discoverability and namespace disambiguation.
managed → const ManagedFunctor
Static entrypoint to the managed functor for discoverability and namespace disambiguation.
switched → const SwitchedFunctor
Static entrypoint to the switched functor for discoverability and namespace disambiguation.