Skip to main content

4  Declarations, Bindings & Modules

This chapter specifies value bindings, mutability rules, separate function signatures, #type declarations, and module/visibility directives.

4.1 Value bindings and mutability

Binding Form Syntax Scope & Mutability Rules & Diagnostics
Immutable binding x = expr Local or module constant Immutable after binding; reassigning x = v emits E3033
Primed local rebinding x' = expr
x'' = expr
Local mutable / stepped SSA binding Once primed (x' = 0), subsequent updates in the same scope may write x' = v, x = v, or x'' = v
Mutable module global ::g = expr Module-wide mutable state Readable as g or ::g; writable inside functions as g = v, ::g = v, or g ::= v (E3033 if g was not declared with ::)
Forward type annotation x: Type (own line) Local or module declaration Declares the static type of x before assignment; allocates no zeroed storage (E3045 if read before write; E3130 on partial record init)
Inline type + value x: Type = expr Forbidden Rejected with E2009; place x: Type on the line preceding x = expr
Discard assignment _ = expr Forbidden Rejected with E2044; invoke side-effecting calls directly as statements
#use io

::counter = 0

bump: Int => Int
bump = delta =>
   counter = counter + delta
   acc' = counter
   acc' = acc' * 2
   acc'

io::out $ bump(5)   // 10

4.2 Function signatures and definitions

Function types and parameter names are separated onto consecutive declarations:

Form Syntax Semantics Diagnostic
Multi-parameter signature f: T1, T2 => R Declares positional parameter types and return type R E3084: body type mismatch
Nullary signature f: () => R Declares a 0-argument function returning R —
Void return signature f: T1 => () Declares a side-effecting function returning Unit (void) E2104: () used as value expr
Compile-time parameter f: #! T: Type, T => R
f: #! N: Int => R
Declares compile-time Type or constant parameter specialized per call site E3129: Type lowered at runtime
Function definition f = a, b => body Bare parameter names (never parenthesized (a, b) =>) followed by => and expression or indented block E2040: explicit _ parameter
Nullary definition f = !=> body 0-argument function body; invoked with postfix ! (f!) —
Unannotated function f = a, b => a + b Inferred via static unification across body and call sites; never defaults unknown types to Int E3103 / E3128: ambiguous or underconstrained type
#use io

clamp_low: Int, Int => Int
clamp_low = val, floor =>
   val < floor | floor | val

banner: () => String
banner = !=> "ready"

io::out $ clamp_low(-3, 0)
io::out $ banner!

4.3 Type declarations (#type)

#type registers a nominal or structural type in the current module scope:

Type Category Syntax Representation & Semantics
Scalar / type alias #type UserId Int Alias for an existing primitive or composite type
Named record #type Point (x: Int, y: Int = 0) C-ABI aligned product type; fields may specify default values (= expr) used by Point(...) and Point.zero
Multiline record #type Point
x: Int
y: Int
Indented or parenthesized multiline field list; newline separates aligned fields
Positional tuple #type Pair (Int, String) Positional fields accessed via .0, .1, …
Homogeneous tuple / SIMD #type Vec4 (Float * 4) Contiguous inline repetition of N elements; supports SIMD arithmetic and intrinsics
Packed / aligned record #type Hdr #packed #align 4 (...) #packed removes padding; #align N enforces power-of-two byte alignment N
Bitfield record #type Flags #packed u16 (syn: <>, ack: <>, res: 14) Packs 1-bit <> flags and integer bit widths into u8, u16, u32, or u64 (E2055 if sum exceeds backing width)
Growable array #type Ints Int{} / #type Buf u8{256} 24-byte { len, data, cap } arena-backed dynamic array (optional default capacity {cap})
Slice #type View Int[] 16-byte { len, data } non-owning contiguous view
Hash map #type Dict String ^ Int Arena-backed open-addressed hash table (Key in String, Int, Addr)
Ramification #type Opt < Int | >
#type Res < Int | Error >
Two-slot positional sum type (RamPN, RamNP, or RamPP)
Nominal enum #type Expr < Lit(Int), Add(Expr, Expr), Nop > 16-byte { i64 tag, ptr payload } tagged union with \(\ge 2\) uppercase variants (E2070, E2012, E2074)
Type generator (#!) Box: #! T: Type => (val: T)
#type IntBox Box(Int)
Compile-time function returning a Type, instantiated via #type

4.4 Modules, visibility, and FFI directives

Directive Syntax Scope & Semantics Diagnostic
Standard / local import #use io
#use "lexer"
#use net/http
Resolves relative .dva files first, then std/<name>.dva. Binds module under its last path segment (io::out, http::get) E5001: module not found
E5002: circular import
Package import #use @pkg
#use @pkg/sub
Resolves external dependency declared in edva.ccl via .edva/imports.ccl E7001–E7021: package errors
Public visibility #public / #pub
#public f: Int => Int
Alone on a line: sets default visibility to public for subsequent declarations. Prefixing a declaration: exports that single symbol/type E3005: private symbol access
Private visibility #private / #priv
#private helper = ...
Alone on a line: resets default visibility to module-private. Prefixing a declaration: marks that single symbol private —
Foreign C import #foreign "c" puts: Addr => i32
#foreign "m" cos: Float => Float
Declares an external C ABI symbol from library "c", "m", or a library path; requires an explicit type signature E2060: missing foreign signature
C ABI export #export add: Int, Int => Int Emits an unmangled C-callable symbol with platform C calling convention —
Compile-time size / align #size Type
#align Type
Evaluates to the target ABI byte size or byte alignment of Type as a compile-time Int —