On this page
Supporting types: state, coordinates, collections, and callbacks
Manual contents | State management | Tools and utilities | Quick reference | Alphabetical index
This reference explains the small types used by the Main, Patch, and Turtle APIs. Examples assume aligned lifecycle where a running world is involved. It is not a reference for Stocks, integration machinery, or every class in the runtime. A type's existence does not make its internal lifecycle methods safe to call directly.
1. Store: current, next, and initial
Source: store.js.
Import with import {Store} from "@nwk/api/store.js";.
A Store holds arbitrary values, not just numbers. It has no automatic numeric
validation, cloning, commitment schedule, or ownership inference.
| Member | Contract |
|---|---|
constructor(obj) |
Evaluate obj() if it is a function, otherwise use obj directly. Initialize current/next and retain obj as reset baseline/factory. Omitted argument gives undefined. |
get() |
Return current value. |
next (get/set) |
Read/replace pending value. Assignment calls the installed nextPinger, even for an equal value. Current/baseline unchanged. |
set(val) |
Immediate current/next edit; baseline unchanged. Calls nextPinger via next assignment, optional pinger(), then change listeners. Does not evaluate a function value. |
initialize(obj) |
Evaluate factory if supplied; replace current/next and baseline. Calls nextPinger via next assignment, initializePinger(value), then change listeners. |
reinitialize() |
Call initialize(initial), rerunning a retained factory if present. Does not clear updater/listeners. |
shift() |
Commit next to current, notify change listeners, return new current. Next remains unchanged. In a running model let the runtime call it. |
setUpdater(f) |
Install updater; does not execute or schedule it. |
autoNext() |
If updater truthy, call it with no arguments and assign result to next. No current change or validation. Custom Store updaters require explicit evaluation by model code. |
addListener(listener) |
Append callback (store, oldValue, newValue), without deduplication/removal API. |
toString() |
Diagnostic string <current, next>; no commitment. |
Store.create(obj, main) |
Static factory: new Store, add to main.stores, synchronize, return Store. Does not guarantee that the owning Main's overridden reset will restore it. Prefer explicit ownership as in the guides. |
Except shift/get/toString and the static factory, methods return undefined. Exceptions in factories/updaters/listeners propagate; operations do not roll back earlier mutations.
This standalone example calls shift itself to expose the distinction:
import {Store} from "@nwk/api/store.js";
const state = new Store(2);
state.next = 3;
const before = state.get();
state.shift();
const committed = state.get();
state.set(4);
state.reinitialize();
const restored = state.get();
before is 2, committed 3, restored 2. In a model, allocate once, call main.synchronize(state) once, propose with next, and restore explicitly in the owner's reset. Built-in properties already provide synchronization; use their public interfaces instead of private Stores. See state management.
Fields, notifications, and mutable values
current,initial,updater, andlistenersare implementation fields. Prefer methods/properties; direct current writes bypass synchronization and notification._nextis backing storage;initialValueis populated by initialize, not by construction.virginis a runtime initialization flag, based on the truthiness of the constructor's evaluated value, then false after initialize. It is not a general "has never changed" flag.nextPingeris assigned by synchronization helpers; replacing it replaces that wiring.initializePingeris an optional one-argument callback receiving the new value;pingeris an optional zero-argument set callback. CapitalizedInitializePingeris not a Store callback.- Change listeners fire even for equal-value shifts. initialize/reinitialize reports a falsy old value as null; set/shift preserve the actual old value. Registration has no equality guard or disposal mechanism.
Objects/arrays are shared by reference. In-place mutation can change current, next, and reset baseline together. A reset factory creates fresh state:
const bag = new Store(() => ({food: 4}));
const original = bag.get();
bag.next = {food: 1};
bag.shift();
bag.reinitialize();
const fresh = bag.get();
fresh is a new {food: 4}, distinct from original. Factory evaluation is
specific to constructor/initialize/reinitialize; assigning next a function
stores a function rather than running it.
The same module exports Pinger, a minimal legacy wrapper whose
constructor(ping) stores a .ping field. It does not subscribe, call the
function, synchronize, or define reset policy. Ordinary models do not need it.
2. Property: immediate value with removable listeners
Source: tools.js.
Property is not a Store: no next, shift, reset baseline, or synchronization.
| Member | Contract |
|---|---|
constructor(value = null) |
Hold value immediately and allocate listener Set. |
value (get/set) |
Always store assigned value; notify only if old and new are not loosely equal. |
get(), set(value) |
Method aliases for value. set returns undefined. |
addListener(f) |
Add f(property, oldValue, newValue) to Set; same function deduplicates. |
removeListener(f) |
Remove that exact function identity; no effect if absent. |
Changing number 1 to string "1" stores the string but suppresses notification. Mutating an object in place is not detected. Listeners execute synchronously; exceptions propagate. Use Property for an immediate selection/control value, not a synchronous environmental quantity.
import {Property} from "@nwk/api/tools.js";
const selected = new Property(1);
const observations = [];
const listener = (property, oldValue, value) => observations.push([oldValue, value]);
selected.addListener(listener);
selected.value = "1";
selected.set(2);
selected.removeListener(listener);
selected.set(3);
observations contains just ["1", 2], nested as one entry.
3. Coordinates and CoordsFactory
Source: coordsfactory.js.
CoordsFactory is exported; its Coords implementation is not.
Normally obtain coordinates with this.newCoords(x, y), not a direct import of
Coords. Creating coordinates neither moves/indexes an agent nor wraps/clamps.
| Factory member | Contract |
|---|---|
constructor(colDim, rowDim) |
Retain dimension fields; create does not use them to normalize coordinates. |
create(x, y) |
Return a fresh coordinate object each call, without validation/coercion. |
reset() |
No-op; does not invalidate existing objects or deduplicate future ones. |
| Coordinate member | Contract |
|---|---|
constructor(x, y) |
Internal construction retaining _x/_y. |
x, y |
Read-only accessors; use numeric properties, not x()/y(). |
distanceTo(other) |
Raw direct Euclidean distance using other.x/y; no boundary or hex scaling. |
sameCell(other) |
Compare floored internal coordinates; expects another compatible coordinate object, not just arbitrary public x/y data. |
hexify() |
Mutate x to doubled-column address 2*x + (y % 2 === 1 ? 1 : 0). Not idempotent and not a general continuous physical-coordinate conversion. |
equals(other) |
Defective legacy method calls numeric _x/_y as functions; throws for normal coordinates. Compare numeric x/y explicitly, with a tolerance when appropriate. |
toString() |
String (x, y). |
Two coordinates with the same numbers are not the same object identity; Set/includes deduplicates identity, not coordinate equality.
import {CoordsFactory} from "@nwk/api/coordsfactory.js";
const factory = new CoordsFactory(10, 10);
const a = factory.create(1.5, 2.5);
const b = factory.create(1.5, 2.5);
const samePosition = a.x === b.x && a.y === b.y;
const sameObject = a === b;
samePosition is true, sameObject false. Movement calculations accumulate floating-point roundoff; use a tolerance rather than exact equality for such positions. Repaired radius/query helpers accept finite public x/y or col/row objects, sometimes legacy callable coordinates too; this does not change the requirements of every older coordinate method.
4. Collections: know what the operation returns
Sources: nlmatrix.js, nlvector.js, and agentgrid.js.
| Type / common source | Read and iterate | Important distinction |
|---|---|---|
| Array, e.g. patches.toList() or Main neighbors | length, for…of, filter/map/reduce | Snapshot of references, not cloned agents/patches. |
| Set, e.g. patch.ring/block | size, values(), for…of | Unique object identities; no native array map/filter. Convert with […set]. |
| AgentSet, e.g. turtle.nhoodPatches | Set subclass | Constructor arguments are col/row metadata, not an iterable initializer. Query methods already fill it. |
| AgentList, e.g. patch.myTurtles() | Array subclass | Array methods work; some return the subclass rather than a plain array. |
| NLMatrix, Main patches | get(col,row), toList(), forEach(patch), filter(predicate) | Not an array. Its visit(visitor) supplies (col,row), not patch. Hex skips invalid parity sites. |
| NLVector, Main turtles | size/length, get(id), values() | Map-backed population; not an array or iterable vector. Convert values() with spread. Membership is not local-query visibility. |
| Iterator, e.g. turtles.values() | for…of or […iterator] | Can be consumed; array methods/iterator helpers are not universally interchangeable. |
NLMatrix.forEach/filter call callbacks with patch values; array callback arguments can also include index/array. Matrix visit instead takes coordinates. Avoid inherited NLRoot.filter's legacy matrix overload; use patches.toList().filter(predicate).
AgentSet and AgentList details
| Member | Contract |
|---|---|
AgentSet.constructor(x, y) |
Empty Set with col/row fields. Normal Set add/delete/size operations are inherited. |
AgentSet.toList() |
New AgentList excluding zombie/newbie entries; references actual visible turtles. Does not delete hidden entries from the Set. |
AgentSet.sortByDistanceFrom(agent) |
New plain array of all Set entries sorted by their distanceTo(agent). Unlike toList, does not filter zombie/newbie. Does not mutate Set. |
AgentSet.toString() |
Returns an array of each member's toString result, not a joined string. |
AgentList.constructor(...args) |
Delegates to Array; standard Array construction semantics apply. |
AgentList.sortByDistanceFrom(agent) |
Sort this list in place and return it, using each member's distanceTo(agent). Raw Turtle distance is not wrapped physical distance. |
Do not edit occupancy Sets or population maps directly to create/remove agents; runtime insertion/unlinking maintains relationships. Main population traversal includes entries that may still be hidden from local queries. Snapshots retain old turtle references after death/world reset; fetch residents again when needed. See population timing.
5. Callback signature lookup
A callback is a function passed to an operation. It is not automatically executed with this bound to the visited object. Arrow functions retain enclosing this; ordinary callbacks need the documented arguments/binding.
| Operation | Callback arguments / binding |
|---|---|
| Patch neighborVisit/ringVisit/blockVisit | (patch), no patch this binding |
| Main turtleVisit | (turtle), scans population rather than filtered occupancy |
| Array filter/map/forEach | (value, index, array); use value for the model object |
| Set forEach | (value, value, set), not an array index |
| NLMatrix.visit | (col, row), not a patch object |
| Store updater / public built-in updater | No arguments, invoked on Store; use arrow closure for model this |
| Store initialization listener | (newValue) |
| Store change listener | (store, oldValue, newValue) |
| Property listener | (property, oldValue, newValue) |
| Main initializeTurtles customization | (turtle), after its init and before coordinated setup; current implementation calls it as a Main method, so ordinary-function this is Main |
| Main createTurtleFromParent customization | (child), ordinary function this bound to parent |
| Main createTurtleFromPatch customization | (child), ordinary function this bound to patch |
| Main createTurtleFromSpecs customization | (child), ordinary call with no special this |
| Parameter-manager listener | (parameterMap, oldValue, newValue); not a Property or Store |
| NLRoot max_one_of_value | Tuple elements expanded as callback arguments; unlike other score helpers |
Callbacks are synchronous unless the particular API says otherwise. Returning false from a patch visitor does not break the traversal. These operations do not provide transaction rollback after a callback throws.
6. Enums and runtime choices
Source: tools.js.
| Type | Representation and operations |
|---|---|
Enum(...slots) |
Supply slot objects with unique name fields. Mutates slots to add ord and toString; result[name] is that object. values() returns the retained slot array; ordinal(slot) reads slot.ord without membership validation. |
EnumSym(...names) |
Supply names; result[name] is a distinct Symbol. values() returns retained Symbol array; ordinal(symbol) returns index or -1. |
The result object is frozen, but its values array and Enum slot objects are not deeply frozen. Do not mutate them or reuse names such as values/ordinal which collide with helper members. Neither constructor validates a schema. Symbols are not portable JSON configuration values.
import {Enum, EnumSym} from "@nwk/api/tools.js";
const Health = Enum({name: "Susceptible"}, {name: "Infected"});
const Mode = EnumSym("Searching", "Resting");
const paletteIndex = Health.Infected.ord;
const selectedMode = Mode.Searching;
paletteIndex is 1; selectedMode is a Symbol, not the string "Searching". Use the slot when identity matters and ord when a numeric palette value is required. See named-state examples.
Supplied choices
| Module | Exported choice types / entries |
|---|---|
| nlsimmain | Shape: Circle, Rectangle; VisitMode: No, C_A, A_C, C/A, A/C, C, A, SD, SDRK4 |
| nlsimmain | Dir (Enum slots): E, SE, S, SW, W, NW, N, NE, with theta/dx/dy |
| nlmatrix | BoundaryMode: Wrap, Edge |
| nlvector | MoveMode: Trajectory, Next_Location; MotionMode: Continuous, Discrete; CollisionMode: None, Gas; EdgeMode: Bounce, Wrap, Stop |
All except Dir use EnumSym. Project uses corresponding strings, with its shape spellings "circle"/"rectangle"; runtime Turtle shape uses Shape Symbols. Dir diagonals have grid offsets +/-1, not Euclidean unit vectors. Do not confuse cell BoundaryMode with agent EdgeMode. See Project configuration for what each selection controls.
7. Scope and verification
The guide tests inventory the Store, Property, coordinate-factory/coordinate, AgentSet, and AgentList declarations documented here, execute this page's examples, and check mutable factory reset, notification arguments, visibility filtering, and sorting mutation. Existing guide tests exercise enum identity, population/index timing, array payload shapes, and synchronous state behavior.
This is not a per-member reference for internal AgentGrid/NLMatrix/NLVector construction, collision machinery, parameter/display managers, or Stocks. Their model-facing use is described here and in the class references. No runtime behavior is changed, and unsupported legacy methods remain labeled.