Skip to content

6.2.3. Aggregate Family

6.2.3.1. When To Use It

Use AggregateVM1 through AggregateVM6 when the parent owns a fixed set of heterogeneous children and each slot has a stable semantic role: workspace shells, multi-pane roots, dashboards, or status bundles.

This is the right primitive when "component 1" and "component 2" mean different things and variable-length child lists would weaken the contract.

Aggregate Family Map

HTML · SVG · PNG

6.2.3.2. Shape And Ownership

An aggregate is a component-shaped parent with named child slots:

  • Component1 is always present on every arity.
  • Higher arities add Component2 through Component6.
  • Each slot is populated lazily through a factory during construct().

The explicit arity surface is deliberate. VMx keeps AggregateVM1 through AggregateVM6 rather than a variadic abstraction so every flavor preserves the same compile-time slot contract.

Aggregate slots are fixed ownership positions. All factories are evaluated and validated before any existing slot is overwritten. A duplicate identity, an already-owned component, or an ownership cycle rejects the population without changing prior slots. A populated aggregate child cannot be transferred into a mutable container because that would leave an invalid empty slot.

6.2.3.3. Lifecycle And Messaging

Construction and destruction cascade through the slot children:

  1. slot factories run during construct()
  2. each populated child is constructed
  3. the aggregate reaches Constructed only after every child does

Each successful slot population publishes a property-changed message for that slot (Component1, component_1, component1, and so on).

Reconstruction is transactional across every slot. VMx creates and validates all candidates before disposing old slots. It continues cleanup after a slot failure, remembers the first failure, and then either commits every viable candidate together or disposes them all if the aggregate became terminal. Factory or ownership preflight failure leaves all old slots and parent links unchanged. Concurrent disposal waits for this decision, so it never observes a half-replaced aggregate.

6.2.3.4. Cross-Language Surface

Concept C# Python TypeScript Swift Rust
Arity-6 type AggregateVM6<...> AggregateVM6[...] AggregateVM6<...> AggregateVM6<...> AggregateVm6<...>
Slot builder setters Component1(...) component_1(...) component1(...) component1(...) component_1(...)
Slot property Component1 component_1 component1 component1 component_1()

6.2.3.5. Example

  • C#: AggregateVM6<...>.Builder().Name("workspace").Services(hub, dispatcher).Component1(() => notebooks).Component2(() => notes).Build()
  • Python: AggregateVM6Builder[...]().name("workspace").services(hub, dispatcher).component_1(lambda: notebooks).component_2(lambda: notes).build()
  • TypeScript: AggregateVM6.builder<...>().name("workspace").services(hub, dispatcher).component1(() => notebooks).component2(() => notes).build()
  • Swift: try AggregateVM6<...>.builder().name("workspace").services(hub: hub, dispatcher: dispatcher).component1 { notebooks }.component2 { notes }.build()
  • Rust: AggregateVm6::<...>::builder().name("workspace").services(hub, dispatcher).component_1(|| notebooks.clone()).component_2(|| notes.clone()).build()?

The Notes Workspace shell uses this pattern as its six-pane root in the C#, Python, TypeScript, and Swift examples.

Rust implements the same aggregate type and builder shape. Its slot-notification and construction ordering evidence is recorded in the completed Rust parity ledger.

6.2.3.6. Common Pitfalls

  • Using an aggregate when the child set is variable or homogeneous. Prefer CompositeVM or GroupVM.
  • Expecting slot factories to run at build time. They run at construct time.
  • Passing a component that is still owned by a composite or group. Remove it explicitly before returning it from an aggregate factory.
  • Flattening semantic slots into a list and losing explicit ownership names.
  • Treating slot children as selectable peers. Aggregates own structure, not a Current selection slot.