This chapter specifies value bindings, mutability rules, separate function signatures, #type declarations, and module/visibility directives.
Value bindings and mutability
| 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
Function signatures and definitions
Function types and parameter names are separated onto consecutive declarations:
| 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!
Type declarations (#type)
#type registers a nominal or structural type in the current module scope:
| 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 |
Modules, visibility, and FFI directives
| 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 |
— |
Audience: Edva users
Status: current reference
Audited: df88a80
Evidence: src/parser.dva, src/annotate.dva,
src/unify.dva, GRAMMAR.md,
tests/pass/121_fn_signatures.dva