Comments, Values, and Classes
Comments begin with -- and run to end of line. let declares a local with a type and an initial value; := is both declaration-assignment and plain reassignment. Equality is =, inequality is /=.
let total: Integer := 3 + 4
total := total + 1
A class groups data (feature) and constructors (create); inside a method, this is the current object and result is the name you assign to for a return value:
class Counter
create
make(start: Integer) do value := start end
feature
value: Integer
increment() do value := value + 1 end
current(): Integer do result := value end
end
let c: Counter := create Counter.make(0)
c.increment()
A no-argument method may be called without parentheses — store.tasks rather than store.tasks() — which is why several listings in this book read a field-like value with no trailing ().
Generics, Arrays, and Maps
Type parameters go in square brackets: class Lru_Cache [K, V] (Chapter 3). The two collections every project in this book uses are Array[T] and Map[K, V]:
let xs: Array[Integer] := [1, 2, 3]
xs.add(4)
let first: Integer := xs.get(0)
let prices: Map[String, Integer] := {}
prices.set("apple", 150)
if prices.contains_key("apple") then ... end
Any is the top type every value inherits, used where a project deliberately steps outside static typing — parsing untyped JSON in Chapters 2, 7, and 9 is the only place this book does that.
Detachable Types: ?T
A leading ? on a type marks it detachable — it may hold nil. Task_Store.find in Chapter 2 returns ?Task: either a real task, or nothing, stated in the type rather than left to a caller's memory of whether a sentinel value might come back instead.
let t: ?Task := store.find(id)
if t /= nil then
t.mark_done()
end
Sum Types: union and match
A sum type — a value that is exactly one of a closed set of shapes — is written union, one line per shape:
union Task_Status
Open
Done
end
match takes a sum type apart, and because the set of shapes is closed, the compiler requires every case to be handled — a missing one is a compile error, not a runtime surprise:
match status of
when Done then result := true
when Open then result := false
end
A when pattern can also destructure fields carried by a shape — when Bin_Op(op, left, right) then ... in Chapter 4's expression AST binds three locals directly from the matched variant.
Refinement Types
A refinement type narrows an existing type with a predicate, in one line, with no wrapper class — at runtime, the value is its base type:
declare type Priority = Integer where p: p >= 1 and p <= 5
The predicate is checked wherever a plain value is narrowed into the refined type — a parameter, a typed let — and never again; code that already holds a Priority can trust the range without re-checking it. Chapter 2 develops this fully.
Contracts
Contracts are ordinary syntax, not a library, and every chapter in this book uses at least one of the three forms below.
require— a precondition, checked before a method runs: what the caller must already guarantee.ensure— a postcondition, checked on return: what the method itself guarantees.old erefers toe's value on entry.invariant— a property that holds of every instance of a class, before and after every method call (Chapter 3 builds a whole library around one).
add(text: String, priority: Priority): Integer
require
non_empty: text /= ""
do
...
ensure
grew: tasks.length = old tasks.length + 1
end
Each clause has a name (non_empty, grew); a violated contract reports which named promise broke, which is the entire reason this book keeps calling contracts more informative than a generic exception.
Functions and Loops
A free-standing function is written with function. The loop form used throughout this book is from ... until ... do ... end — the from block initializes, the loop runs until its condition becomes true:
let i: Integer := 0
from
i := 0
until
i = xs.length
do
...
i := i + 1
end
An anonymous function is written fn(params): ReturnType do ... end — Chapter 7's HTTP route handler and Chapter 5's sort comparator are both written this way, passed directly where a callback is expected.
Concurrency: Task, spawn, Channel
spawn do ... end starts a block of code running concurrently and returns a Task[T] handle to it — nothing about the syntax differs from an ordinary block, which is deliberate:
let t: Task[Integer] := spawn do
result := expensive_computation()
end
let value: Integer := t.await()
await_all takes an array of tasks and waits for every one, returning their results in order — Chapter 5's fan-out/fan-in over one file-read task per file is the clearest example in this book. Channel[T] is a typed, thread-safe queue for message passing between tasks, rather than shared mutable state guarded by a lock — Chapter 6's chat hub is built entirely around one.
intern and Java Interop
intern <Name> loads another Nex module by name, resolved against a file whose snake_case name matches; Appendix C covers the naming rule this implies in full. import brings in a Java class by its fully-qualified name, and Java code is called from inside a with "java" do ... end block — only Chapter 8 and Chapter 9's dashboards use either. A Nex class implements a Java interface the same way it inherits a Nex one, with inherit:
class Increment_Listener
inherit
ActionListener
...
actionPerformed(e: ActionEvent) do
state.increment()
end
end
That is the whole vocabulary this book's listings depend on. Where a construct does something subtle, the chapter it appears in explains it in place.