Composition articles and compiler notes mixed informal wiring guidance with normative host syntax.
Native dependency injection
Platform spec feature
Native dependency injection
Spec standingStandard
-
Sibling articles defer to this hub for MUST/SHOULD authority.
Context
Decision
This feature hub must own normative MUST/SHOULD contract text. Sibling articles must not redefine hub requirements and should link here for authority.
Consequences
FAQ locked decisions migrate to ADRs; articles retain examples and troubleshooting tables only.
Verification anchors
/platform-spec/language-meta/composition/dependency-injection/;
verify:trudoc. -
Backends do not perform runtime service lookup for app DI.
Context
Runtime DI containers hide wiring and conflict with the project's explicit composition goals (distinct from Rust pipeline IoC in D-INC-0002).
Decision
The reference compiler must fully resolve the app composition graph at compile time. Backends must not perform runtime service lookup for
host/registry/scopewiring.Consequences
Lowering emits ctor wiring and scope enter/leave; execution hosts activate frozen graphs only.
Verification anchors
compiler/crates/beskid_analysis(plannedcompositionmodule);compiler/crates/beskid_codegen; Flow and algorithm. -
Constructor parameter inject is rejected (E1712).
Context
Constructor injection churns signatures across inheritance and complicates lowering.
Decision
injectmust apply to fields on ordinary types only. Constructor-parameterinjectmust be rejected (E1712).Consequences
Uniform type headers and a single slot-lowering story for injected fields.
Verification anchors
-
Global registrations use registry block name registry.
Context
Early drafts considered alternate container keywords.
Decision
The global registration block must be spelled
registry(locked for v0.2+).Consequences
Parser, diagnostics, and docs use one keyword; no alias
containerin Standard conformance.Verification anchors
Grammar and semantic snapshots when composition lands.
-
Resolution walks innermost named scope toward global.
Context
Authors need predictable scope boundaries for web and console activation patterns.
Decision
Construct Rule Global Merged registryof the launched host after inheritance chainNamed scopeTree under global; per-activation unless single/transientStack Fiber-local scope stack during withResolution Walk innermost → global; global::andparent::qualifiers as specifiedConsequences
Execution backends maintain scope enter/leave with
with; plural inject collects at lowest matching level.Verification anchors
-
Singular inject must be unique at the resolution level.
Context
Apps register multiple implementations of one contract (for example two
Storage).Decision
Multiple implementations must use
inject Contract[](or concreteT[]). Singularinject Contractmust be unique at the resolution level (E1705 when ambiguous).Consequences
Deterministic registration merge order defines array element order.
Verification anchors
-
Exactly one launch per process invocation.
Context
Libraries ship reusable composition roots; executables pick one entry host per run.
Decision
Projects may declare many named
hosttypes. Each process run must use exactly onelaunch Host(args)on an executable target (E1702 for duplicate launch on one path).Consequences
Manifest
apptargets name the launched host; multi-app repos use separate targets, one launch each run.Verification anchors
-
Libraries may declare host types but not launch.
Context
Test and library packages attempted to embed process entry via launch.
Decision
Libproject targets may declarehosttypes for reuse butlaunchis forbidden (E1711). Only app/test host targets maylaunch.Consequences
Consumers reference library hosts from their own app targets or approved harness entries.
Verification anchors
FAQ.
-
Resolves after semantic.snapshot before mod.analyze.
Context
Compiler mods need a frozen composition snapshot but must not mutate app graphs.
Decision
Pipeline phase
composition.resolvemust run aftersemantic.snapshotand beforemod.analyze(see Stage ordering).Consequences
Mods query read-only snapshots; app graph build stays in analysis.
Verification anchors
compiler/crates/beskid_pipeline; Flow and algorithm. -
Compiler Mod type forbids host blocks on mod projects.
Context
Compiler mods and app DI share syntax keywords but different planes.
Decision
Modprojects must not declare apphostblocks or alter app composition graphs. Mod registration uses contractregistrations[]per Compiler Mod SDK.Consequences
Clear boundary between Pipeline composition (Rust) and app DI (Beskid).
Verification anchors
- Native dependency injection - Contracts and edge cases Lifetime rules, plural inject, host override, fail-closed guarantees, E17xx diagnostics.
- Native dependency injection - Design model host, registry, scope hierarchy, global scope, field inject, array inject, dispose, and launch.
- Native dependency injection - Examples Reference fixtures for hosts, plural inject, scope dispose, and library hosts.
- Native dependency injection - FAQ and troubleshooting Locked design decisions, troubleshooting, and v0.3 follow-ups.
- Native dependency injection - Flow and algorithm Host-chain merge, global scope, composition.resolve, plural inject lowering.
- Native dependency injection - Verification and traceability Tests, snapshot versioning, and implementation checklist.
0 revisions (git unavailable at build; counts may be empty)
No commits recorded for this path.
Full tree: run pnpm verify:platform-spec-layout (writes src/generated/platform-spec-layout-report.json).
Native dependency injection is a language feature: projects declare named host types (including reusable library hosts), register services in registry (global scope), define nested scope containers with init / dispose, activate scopes with with, use field inject (including T[] for multiple implementations), and start the process with a single launch. The reference compiler fully resolves the graph at compile time; backends do not perform runtime service lookup.
Boundaries
Section titled “Boundaries”| Plane | Mechanism |
|---|---|
| App composition (this feature) | host, registry, scope, init, dispose, with, field inject, startup, launch |
| Rust pipeline composition | Pipeline composition — compiler pass/service graph only |
Compiler mods (type: Mod) | Compiler Mod SDK — contract registrations[], not app DI |
| Package dependency graph | Resolution and projects — CompilePlan / lockfile, not service lifetimes |
Mod projects must not declare host blocks or alter app composition graphs. Mod analyzers may query a frozen composition snapshot exported by the compiler (Analysis, query, and diagnostics facades).
Corelib hosts
Section titled “Corelib hosts”Built-in host bases (for example ConsoleHost, future WebHost) live in corelib. An app host may inherit a base (: ConsoleHost) to reuse default registry entries and run-loop behavior. Base-host contracts are specified alongside execution and corelib packages as they land.
Implementation anchors (reference compiler)
Section titled “Implementation anchors (reference compiler)”Anchors name the modules that own each plane of native DI in the reference compiler. The codegen lowering gate (RUNTIME_CONTAINER_LOWERING_ENABLED) is on as of v0.3; launch and with emit real runtime container ABI calls.
compiler/crates/beskid_analysis/src/composition/— host-chain merge, scope tree,BindingPlan,CompositionSnapshotexportcompiler/crates/beskid_codegen/src/lowering/composition_policy.rs—RUNTIME_CONTAINER_LOWERING_ENABLEDfeature gatecompiler/crates/beskid_codegen/src/lowering/composition/—launch/withlowering to runtime container ABI calls (launch_statement.rs,with_statement.rs)compiler/crates/beskid_runtime/src/composition/—RuntimeContainer(registration ordering, plural inject, LIFO dispose) and scope-stack managementcompiler/crates/beskid_runtime/src/builtins/composition.rs—extern "C-unwind"ABI surface (composition_container_create,composition_register,composition_bind_plural,composition_launch,composition_scope_enter,composition_scope_leave,composition_resolve,composition_resolve_plural,composition_shutdown,composition_container_drop,composition_scope_depth)compiler/crates/beskid_abi/src/symbols.rs/compiler/crates/beskid_abi/src/builtins.rs— stable linker symbols andBuiltinFnSpecentries for everycomposition_*builtincompiler/crates/beskid_pipeline—composition.resolvephase id (see Flow and algorithm)compiler/corelib—ConsoleHost,WebHost, shared configuration types
End-to-end verification lives at compiler/crates/beskid_tests/src/composition/ (container.rs, host_e2e.rs, lowering.rs).
Articles
Section titled “Articles”Decisions
Section titled “Decisions”No open decisions. Closed choices are normative ADRs under adr/ (D-LMETA-DI-0001 … D-LMETA-DI-0010); use the reader ADRs tab for detail. Rust compiler-host IoC remains D-INC-0002 (separate plane).