A meaning-first workflow
Denotational Design is a workflow, not only an explanation of finished code: state the semantic change, find the smallest primitive capabilities, compose them truthfully, then implement thin interpreters and check laws.
Denotational Design is most useful as a repeatable development discipline, not only as an explanation of finished code.
The core workflow
For a new feature or refactor:
- State the semantic change in one sentence.
- Identify the carrier and observable equality.
- Find the smallest primitive capabilities required.
- Define derived behavior over explicit capabilities.
- Choose the truthful composition form.
- Reify a first-order program only if structure needs multiple interpretations.
- Implement thin concrete interpreters.
- Add laws or shared scenarios.
- Validate alternative interpretations.
- Document meaning before machinery.
State the semantic change
Weak statement:
Add a cache and a manager method.
Meaning-oriented statement:
Resolving the same immutable source name denotes the same source value during one compilation.
The second statement exposes a candidate law. Caching may later be chosen as one implementation.
Find the primitive boundary
Ask:
- What new observation or transformation is required?
- Is it primitive at this boundary or derivable from existing meaning?
- Is a new associated carrier required?
- Is the supposed dependency only a storage location?
- Which distinctions should remain invisible?
Add a capability only for genuinely new primitive meaning.
Choose composition truthfully
Use this decision table:
| Question | Choice |
|---|---|
| Does one receiver interpret all required meanings? | Direct bounds |
| Is behavior independently selected? | Explicit policy value |
| Are policies independently composable? | Product |
| Does an environment contain another interpreter? | Projection |
| Must a wrapper substitute for the inner interpreter? | Delegation |
Do not introduce a large context trait as the default answer.
Refactor one meaning at a time
When existing code is representation-first:
- Identify one semantic observation.
- Define one small capability.
- Move one derivation into an extension.
- Keep the current struct as its interpreter.
- Add one law-style test.
Avoid rewriting an entire subsystem into speculative abstractions. DD is not abstraction maximalism.
Review from meaning to machinery
Read code in this order:
- capability traits
- semantic value types
- derived extensions
- first-order program syntax, if present
- shared laws and scenarios
- concrete interpreters
- runtime orchestration
Starting from the largest state struct biases the review toward its representation.
Common failure modes
trait ContextAlg {
fn state(&self) -> &ConcreteState;
}
The trait changes syntax but not meaning ownership. The semantic core still depends on the concrete representation.
Derived logic in every interpreter
If every implementation independently defines the same domain algorithm, the specification is duplicated.
God capability
A supertrait containing unrelated operations hides the dependency row and prevents independent interpretation.
Framework-owned specification
If route annotations or RPC registration are the only interface definition, documentation and execution can drift.
Macro-owned meaning
If generated code has no public first-order target, the macro expansion becomes the accidental specification.
Policy hidden in defaults
If Default silently chooses quorum, retry, ordering, or compilation policy, composition is no longer explicit.
Tests of private steps
Tests coupled to field layout or traversal order discourage valid alternative interpreters.
Pull request checklist
Meaning
- Is the semantic change stated?
- Is the carrier and equality clear?
- Are intentional omissions named?
Capabilities
- Does each trait expose coherent primitive meaning?
- Are bounds placed where operations use them?
- Does derived code avoid concrete fields?
Composition
- Are direct bounds, policies, products, projections, and delegation used truthfully?
- Are semantic defaults explicit?
Programs and interpreters
- Is first-order structure introduced only when another interpretation needs it?
- Can convenience macros lower to public program values?
- Are concrete interpreters thin and boundary-specific?
Evidence
- Is a law or focused semantic assertion present?
- Can the same scenario run against another interpreter?
- Are finite tests described as evidence rather than proof?
Reading ALUX-style code
The broad shape to recognize is:
- Tiny primitive capability traits
- Derived extensions over explicit bounds
- First-order programs when inspection or composition requires them
- Shared laws and scenarios
- Concrete runtime, compiler, HTTP, RPC, or storage interpreters
Large concurrent systems still contain orchestration-heavy regions. Do not assume every existing interface is already an ideal denotational specification. Look for the semantic seams and read outward from them.
Tolang uses the same perspective at language scale: syntax is normalized into meaning-bearing forms, compilation preserves that meaning, and a concurrent runtime interprets the executable representation. The operational story remains essential, but it comes after the semantic contract.
Final principle
When uncertain, return to one question:
That question does not solve every engineering problem. It makes the problem visible at the correct level.