Design Principles
Calor is built on five core principles that guide every language design decision. These principles serve a deeper goal: enabling verification. Every design choice makes contracts and effects machine-checkable, not just human-readable.
The Five Principles
| Principle | Implementation | Agent Benefit |
|---|---|---|
| Explicit over implicit | Effects declared with §E{cw,fs:r,net:rw} | Know side effects without reading implementation |
| Contracts are code | First-class §Q (requires) and §S (ensures) | Generate tests from specs, verify correctness |
| Everything has an ID | §F{f001:Main}, §L{l001:i:1:100:1} | Precise references that survive refactoring |
| Unambiguous structure | Matched tags §F{}...§/F{} | Parse without semantic analysis |
| Machine-readable semantics | Lisp-style operators (+ a b) | Symbolic manipulation without text parsing |
1. Explicit Over Implicit
In traditional languages, side effects are implicit. You have to read the entire function body to know if it:
- Writes to console
- Reads from files
- Makes network calls
- Accesses a database
Calor requires explicit effect declarations:
§F{f001:SaveUser:pub}
§I{User:user}
§O{bool}
§E{db:rw,net:rw} // Explicit: database and network effects
// ... implementation
§/F{f001}Agent benefit: An agent can immediately filter functions by their effects without analyzing implementation details.
Effect Codes
| Code | Effect |
|---|---|
cw | Console write |
cr | Console read |
fs:w | Filesystem write |
fs:r | Filesystem read |
fs:rw | Filesystem read/write |
net:r | Network read |
net:w | Network write |
net:rw | Network read/write |
db:r | Database read |
db:w | Database write |
db:rw | Database read/write |
2. Contracts Are Code
Preconditions and postconditions aren't comments or assertions buried in code - they're first-class syntax elements:
§F{f001:Divide:pub}
§I{i32:a}
§I{i32:b}
§O{i32}
§Q (!= b 0) // Requires: b is not zero
§Q (>= a 0) // Requires: a is non-negative
§S (>= result 0) // Ensures: result is non-negative
§R (/ a b)
§/F{f001}Agent benefit:
- Automatic test generation from contracts
- Static verification of caller sites
- Clear documentation of function behavior
Contract Syntax
| Tag | Purpose | Example |
|---|---|---|
§Q | Precondition (requires) | §Q (> x 0) |
§S | Postcondition (ensures) | §S (!= result null) |
§Q{message="..."} | With custom error | §Q{message="x must be positive"} (> x 0) |
3. Everything Has an ID
Every structural element has a unique identifier that persists across refactoring:
§M{m001:Calculator} // Module ID: m001
§F{f001:Add:pub} // Function ID: f001
§L{for1:i:1:100:1} // Loop ID: for1
§IF{if1} (> i 50) // Conditional ID: if1
// ...
§/I{if1}
§/L{for1}
§/F{f001}
§/M{m001}Agent benefit:
- "Edit function f001" is unambiguous
- IDs survive code movement and renaming
- No reliance on line numbers that change
ID Conventions
Production code uses ULID-based IDs with kind prefixes:
| Element | Prefix | Example |
|---|---|---|
| Modules | m_ | §M{m_01J5X7K9M2NPQRSTABWXYZ12:Calculator} |
| Functions | f_ | §F{f_01J5X7K9M2NPQRSTABWXYZ12:Add:pub} |
| Classes | c_ | §CL{c_01J5X7K9M2NPQRSTABWXYZ12:MyClass} |
| Methods | mt_ | §MT{mt_01J5X7K9M2NPQRSTABWXYZ12:Process:pub} |
Short test IDs (f001, m001) are allowed only in tests/, docs/, and examples.
Learn more: Stable Identifiers - Why IDs matter and how challenges are overcome
4. Unambiguous Structure
Every opening tag has a matching closing tag with the same ID:
§M{m001:Example}
§F{f001:Main:pub}
§L{for1:i:1:10:1}
§IF{if1} (> i 5)
// ...
§/I{if1}
§/L{for1}
§/F{f001}
§/M{m001}Agent benefit:
- No brace-counting ambiguity
- Parse structure without understanding semantics
- Easy to verify structural correctness
Closing Tag Rules
| Opening | Closing |
|---|---|
§M{id:name} | §/M{id} |
§F{id:name:vis} | §/F{id} |
§L{id:var:from:to:step} | §/L{id} |
§IF{id} condition | §/I{id} |
5. Machine-Readable Semantics
Expressions use Lisp-style prefix notation that's directly manipulable:
// Calor: Clear AST structure
(+ (* a b) (- c d))
// Equivalent infix: Requires precedence parsing
a * b + c - d // Wait, is this (a*b)+(c-d) or a*(b+c)-d?Agent benefit:
- No operator precedence ambiguity
- Direct AST manipulation
- Symbolic computation without parsing
Operators
| Category | Operators |
|---|---|
| Arithmetic | +, -, *, /, % |
| Comparison | ==, !=, <, <=, >, >= |
| Logical | &&, ||, ! |
Principle Interactions
These principles reinforce each other:
- IDs + Closing tags = Unambiguous scope references
- Contracts + Explicit effects = Complete behavioral specification
- Lisp syntax + Contracts = Symbolic verification possible
- IDs + Contracts = Traceable invariants across refactoring
Next
- Stable Identifiers - Deep dive into language-level IDs
- Tradeoffs - What Calor gives up for these principles