Interface Signal<T>

the abstraction that defines what a signal is.

interface Signal<T> {
    id: number;
    rid: number;
    name?: string;
    get(observer_id?): T;
    set?(...args): boolean;
    prerun?(): void;
    run(forced?): SignalUpdateStatus;
    postrun?(): void;
    bindMethod<M>(method_name): Signal<T>[M];
}

Type Parameters

  • T

Properties

id: number

id of this signal in the Context in which it exists.

rid: number

runtime-id of this signal.
it equals to the id on the first, so that the dependencies of this signal can be notified of being observed. but once all dependencies have been notified after the first run, this runtime-id should become 0 (UNTRACKED_ID), so that the dependiencies do not have to re-register this signal as an observer.

name?: string

give a name to this signal for debugging purposes

Methods

  • get the value of this signal, and handle any observing signal's id (observer_id).
    typically, when observer_id is non-zero, this signal should handle it by registering it as an observer through the use of the context's Context.addEdge method.

    Parameters

    • Optional observer_id: number

    Returns T

    Example

    const MySignalClass_Factory = (ctx: Context) => {
    const addEdge = ctx.addEdge
    return class MySignal<T> implements Signal<T> {
    declare value: T
    // ...
    get(observer_id?: TO_ID | UNTRACKED_ID): T {
    // register this.id to observer (if non-zero) in the dependency graph as a directed edge
    if (observer_id) { addEdge(this.id, observer_id) }
    return this.value
    }
    // ...
    }
    }
  • set the value of this signal.
    the meaning of setting a signal's value greatly varies from signal to signal, which is why it is so abstracted.
    however, the returning value must always be a boolean describing whether or not this signal's value has changed compared to its previous value.
    what makes use of the returned value again greatly varies from signal to signal. but it is typically used by the run method to decide whether or not this signal should propagate.
    another purpose of the set method is typically to initiate the ignition of an update cycle in a context, bu using Context.runId. this is how StateSignals and EffectSignals begin an update cycle when their values have changed from the prior value.

    Parameters

    • Rest ...args: any[]

    Returns boolean

    Example

    const MySignalClass_Factory = (ctx: Context) => {
    const runId = ctx.runId
    return class MySignal<T> implements Signal<T> {
    declare value: T
    // ...
    set(new_value: T): boolean {
    const value_has_changed = new_value !== this.value
    if (value_has_changed) {
    runId(this.id)
    return true
    }
    return false
    }
    // ...
    }
    }
  • specify actions that need to be taken before an update cycle has even begun propagating.
    TODO: CURRENTLY NOT IMPLEMENTED. ISSUE: what should the order in which prepruns run be? we do know the FULL set of signal ids that will be visited. but we do not know the subset of ids that WILL BE affected and ran, not until run time of the signal propagation. should ids that might be affected also have their preruns ran? and in what order? because we cannot know the order until propagation runtime.

    Returns void

  • run the actions taken by a signal when it is informed that its dependency signals have been modified/changed.
    the return value should be of the numertic enum kind SignalUpdateStatus, which specifies that this signal has been either been:

    • 1: updated, and therefore this signal's observers should be notified (i.e. ran via their run method)
    • 0: unchanged, and therefore this signal's observers should be notified if this is their only active dependency
    • -1: aborted, and therefore this signal's observer should also abort their run method's execution if they were queued

    this method may also accept an optional forced parameter, which tells the signal that it is being forced to run, even though none of its dependency signals have been executed or changed. this information is useful when coding for signals that can be fired independently, such as StateSignal or EffectSignal.

    Parameters

    • Optional forced: boolean

      was this signal forced to run independently?

    Returns SignalUpdateStatus

    the update status of this signal, specifying whether or not it has changed, or if it has been aborted

  • specify actions that need to be taken after an update cycle has fully propagated till the end.
    the order in which postruns will be executed will be in the reverse order in which they were first encountered (i.e: last in, last out). meaning that if all three signals A, B, and C, had postrun methods on them, and the order of execution was: A -> B -> C, then all postruns will run in the order: [C.postrun, B.postrun, A.postrun] (similar to a stack popping).

    Returns void

  • a utility method defined in SimpleSignal, which allows one to bind a certain method (by name) to this instance of a signal, and therefore make that method freeable/seperable from this signal.
    this method is used by all signal classes's static SignalClass.create method, which is supposed to construct a signal in a fashion similar to SolidJS, and return an array containing important control functions of the created signal. most, if not all, of these control function are generally plain old signal methods that have been bounded to the created signal instance.

    Type Parameters

    Parameters

    • method_name: M

    Returns Signal<T>[M]

Generated using TypeDoc