feat(runtime): dynamic object creation and destruction - #468
Merged
Merged
Conversation
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
6 tasks
devin-ai-integration
Bot
force-pushed
the
feature/dynamic-object-lifecycle
branch
2 times, most recently
from
September 20, 2026 20:03
c3b7d2b to
eff211a
Compare
devin-ai-integration
Bot
changed the base branch from
develop
to
feature/streaming-flows
September 20, 2026 20:03
devin-ai-integration
Bot
force-pushed
the
feature/dynamic-object-lifecycle
branch
from
September 20, 2026 20:09
eff211a to
4a50d1e
Compare
HuiJun
force-pushed
the
feature/dynamic-object-lifecycle
branch
from
September 21, 2026 01:30
5adf252 to
26197a9
Compare
HuiJun
force-pushed
the
feature/dynamic-object-lifecycle
branch
from
September 21, 2026 02:13
26197a9 to
7a39997
Compare
An object created by `new T(args)` while a behavior runs is a first-class occurrence of the run: it has its own identity, begins its life where it is made, is classified by its type and starts the behaviors its type exhibits or performs, so a context holds several objects of one usage and a loop creates one per iteration. Writing an object into a feature classifies it by the feature's type and, where the feature is composite and the object owns no whole yet, adopts it as a portion of the owner. `destroy` ends the occurrence and its portions, terminates the state machine it exhibits and the actions it performs where they stand instead of refusing with ErrOccurrenceLifetime, and releases the object from `all T`; a feature still naming it keeps the value and reading through it is ErrOccurrenceDestroyed. A behavior ended before its first run takes no run, and a snapshot of a graph holding a destroyed object materializes. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ite feature drops A `send new T(...)` now goes through constructObject, so the message object starts the behaviors T exhibits or performs like any other constructed object. A composite feature that stops holding an object it owned releases it, so the composite feature it is written into next owns it and ends it on destroy. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ailed constructor's argument objects Co-Authored-By: jason.han <hanhuijun@gmail.com>
…eep destroyed objects out of the check roots Co-Authored-By: jason.han <hanhuijun@gmail.com>
… no adoption to undo Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ack destroy revives the executors it ended Co-Authored-By: jason.han <hanhuijun@gmail.com>
…eature holds it Co-Authored-By: jason.han <hanhuijun@gmail.com>
… the object Co-Authored-By: jason.han <hanhuijun@gmail.com>
…every argument is stored Every hold under a store defers the behaviors it starts, and constructObject writes the arguments under one store boundary (Context.storedTogether), so a behavior the first argument starts reads the later ones. Intrinsic materialization, which binding resolution uses to inspect an endpoint, is under the same boundary as the ordinary materialization. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ed object was addressed A composite write that would make the holder a portion of itself is refused as ErrOccurrenceLifetime before anything is released, adopted or stored. Destroying an object drops the bus messages addressed to it and its portions; the journal restores them when the destruction is rolled back. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…a check carriersUnder passes over a destroyed object and what it holds, as rootInstances already does for a destroyed root, so a global constraint is not read on a stale part nor made ambiguous by it. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…all T A `=` value that read a feature of an object `destroy` ends, `isDuring` of it, or an extent `all T` is unmaterialized when the lives change (an object created, destroyed, or a performance begun or ended), so reading it again finds the object destroyed or the extent as it is now rather than the cached result. The lives are a dependency source the derivation journal rolls back with the lifetimes. Co-Authored-By: jason.han <hanhuijun@gmail.com>
A journal's mark now captures the trace recorder, so a store or constructor rolled back because a behavior it started failed leaves no records of that behavior's run; a committed store keeps its trace. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Every change of the lives unmaterializes the settled values that read them, a life begun while another value derives included; only the value deriving as the change is made is spared. Co-Authored-By: jason.han <hanhuijun@gmail.com>
HuiJun
force-pushed
the
feature/dynamic-object-lifecycle
branch
from
September 21, 2026 05:44
7a39997 to
ab453f0
Compare
…, ended wholes adopt nothing A held image records that a derived value read the lives and, where it is materialized, links it to the destination's lives (rolled back with a failed materialization). An object its home's composite feature drops moves home to another composite feature still holding it. A composite write giving an ended whole a live portion is refused as ErrOccurrenceLifetime. Co-Authored-By: jason.han <hanhuijun@gmail.com>
…es no portion ending after it Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
An object was materialized once, from its declaration, and nothing destroyed it:
new T(…)built a message-shaped value forsend, an object written into a feature was classified by it but owned by nothing,destroyrefused an object whose state machine was under way (ErrOccurrenceLifetime), and a destroyed object stayed inall T. This is the object-model item the roadmap's addressed-send item (E7) waits on: a context must hold more than one object of one usage and be able to destroy one.Now an object created while a behavior runs is a first-class occurrence of the run:
evalConstructor→Context.constructObject: materialize, thenstartClassifierBehaviors, so anew Car(…)has its own identity, begins its life where it is made, is classified byCarand runs the behaviorsCarexhibits/performs. Twonew Car(…)in one context are two objects; a loop creates one per iteration.SetFeatureValue→Context.holdWritten: the holding feature's type classifies the written object (classifyHeld), and a composite feature (notref) adopts an ownerless object as a portion of the owner (owner/ownerFeature, journaled), sodestroyof the whole ends it.destroy: ends the occurrence and its portions, thenendBehaviorsWithterminates the state machine it exhibits and the actions it performs where they stand; a destroy reached from inside one of them unwinds it asterminatedoes. ThecheckMayEnd/performanceUnderWayrefusal is gone.objectsOfskips destroyed objects, soall Treleases them; a feature still naming one keeps the value and reading through it isErrOccurrenceDestroyed.nextRunnableBehaviordiscards a pending behavior whose object was destroyed before its first run;performanceOccurrenceresolves an already-held performance occurrence without dereferencing the destroyed object, so a held image of such a graph materializes.Spellings are the specifications' only: KerML §7.4.9
new T(args)in any expression position andOccurrenceFunctions::create/addNew/addNewAt. SysML v2 defines no other textual constructor for an occurrence of a definition; the compliance record says so. The addressedsend … to <expr>that picks the second object is not part of this change.Specification basis
KerML 1.0 §7.4.9 (
InstantiationExpression/ConstructorExpression), SysML v2 §7.6 (feature values, occurrence usages), Kernel Semantic LibraryOccurrences.kerml(an occurrence's life;OccurrenceFunctions::create/destroy).docs/project/spec-compliance.md: a new Dynamic object creation row in the Instantiation map, thecreate/destroyrow and theall Trow updated to the new semantics, and the "Dynamic object creation/destruction" bullet removed from Major Features Not Implemented.docs/project/roadmap.mdrecords the item as landed and unblocks E7.How it was verified
object_created_by_constructorandobject_destroyed_at_runtime, each with a trace golden (create: Car #nper object;destroy: Car #5followed by the terminated machine, no later run).robustness_object_lifecycle_test.goTestRuntimeRobustnessObjectLifecycle: two objects of one usage distinct and held, creation in a loop, destroy through a reference, destroy ends the created object's machine, destroy twice refused, destroy of the whole ends created parts, deterministicexploreover creating branches, a destroy/read race reaching exactly two outcomes.TestDestroyRefusedWhilePerformingbecameTestDestroyEndsTheMachinePerformed.go build ./...,go vet ./...,gofmt -l .empty,python3 scripts/changelog.py check,python3 scripts/check-doc-ids.py, andgo test ./...withOPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI=1all green (the one timing testTestFormattingDiffIsCheaperThanFormattingfailed once under the full parallel run and passes with-count=3alone).new Carthe fleet lists[Instance(ID: 5), Instance(ID: 7)]in%featuresandsize(all test::Car)counts them.Checklist
make testandmake lintpass locallychanges/unreleased/<slug>.<section>.md, not as an edit toCHANGELOG.mdmake docs-countsrun if a gate count moved (compliance rows need nothing: the census is counted at docs build)F4,K5) in the body, docs, or changelog