Every construct in Nex — one card at a time.
-- This is a comment. The computer ignores it.
-- Use comments to explain your code to other humans!
let name: String := "Alice" -- a piece of text (String)
let age: Integer := 10 -- a whole number (Integer)
let height: Real := 4.5 -- a decimal number (Real)
let likes_cats: Boolean := true -- true or false (Boolean)
Real literals must include at least one digit after the decimal point. Valid examples: 4.5, 10.0, .5, 12.0e-3. Invalid: 10., 12.e-3.
print("Hello, world!")
print(name)
print("I am " + age + " years old")
let sum: Integer := 3 + 4 -- 7
let diff: Integer := 10 - 3 -- 7
let product: Integer := 5 * 6 -- 30
let quotient: Integer := 20 / 4 -- 5
let remainder: Integer := 10 % 3 -- 1
let power: Integer := 2 ^ 8 -- 256
Integer literals can also be written with explicit bases:
let flags: Integer := 0b1111_0000
let perms: Integer := 0o755
let color: Integer := 0xFF_AA_33
Use lowercase prefixes 0b, 0o, and 0x. _ may be used as a digit separator.
x = y -- equal?
x /= y -- not equal?
x == y -- same object?
x != y -- different object?
x < y x <= y -- less than? less or equal?
x > y x >= y -- greater than? greater or equal?
x and y -- both true?
x or y -- at least one true?
not x -- flip true/false
Nex has two kinds of equality:
= and /= compare by value== and != compare by identityprint([1, 2] = [1, 2]) -- true
print("abc" = "abc") -- true
let a := [1, 2]
let b := a
let c := [1, 2]
print(a == b) -- true
print(a == c) -- false
if age >= 18 then
print("You can vote!")
elseif age >= 13 then
print("You are a teenager")
else
print("You are a kid")
end
let label: String := when age >= 18 "adult" else "minor" end
from let i: Integer := 1 until i > 5 do
print(i)
i := i + 1
end
-- prints 1 2 3 4 5
repeat 3 do
print("hello!")
end
-- prints hello! three times
Iterate over any collection (Array, String, Map) using its cursor:
across [10, 20, 30] as x do
print(x)
end
-- prints 10 20 30
Strings iterate by character:
across "abc" as ch do
print(ch)
end
-- prints #a #b #c
Maps iterate as [key, value] pairs:
across {"name": "Alice", "age": "10"} as pair do
print(pair.get(0))
end
function greet(name: String)
do
print("Hello, " + name + "!")
end
greet("Bob")
A function that gives back a value:
function double(n: Integer): Integer
do
result := n * 2
end
print(double(5)) -- 10
For mutually recursive functions, declare the signatures first:
function is_even(n: Integer): Boolean
function is_odd(n: Integer): Boolean
function is_even(n: Integer): Boolean
do
if n = 0 then result := true
else result := is_odd(n - 1) end
end
function is_odd(n: Integer): Boolean
do
if n = 0 then result := false
else result := is_even(n - 1) end
end
let colors: Array [String] := ["red", "green", "blue"]
print(colors.get(0)) -- "red"
colors.add("yellow") -- add to the end
print(colors.length) -- 4
let pet: Map [String, String] := {"name": "Max", "kind": "dog"}
print(pet.get("name")) -- "Max"
pet.put("kind", "cat") -- update a value
Use a set when you want an unordered collection of distinct values.
let evens: Set[Integer] := #{0, 2, 4}
print(evens.contains(2)) -- true
An empty set uses the explicit set literal syntax:
let empty: Set[Integer] := #{}
Build a set from an array (duplicates are removed):
let numbers: Set[Integer] := create Set[Integer].from_array([1, 2, 2, 3])
print(numbers.size) -- 3
Set operations:
let a: Set[Integer] := #{1, 2, 3}
let b: Set[Integer] := #{3, 4}
print(a.union(b)) -- #{1, 2, 3, 4}
print(a.intersection(b)) -- #{3}
print(a.difference(b)) -- #{1, 2}
Use spawn to start a lightweight task:
let t: Task[Integer] := spawn do
result := 1 + 2
end
print(t.await) -- 3
print(t.is_done) -- true
Use Channel[T] to communicate between tasks:
let ch: Channel[Integer] := create Channel[Integer]
spawn do
ch.send(42)
end
print(ch.receive) -- 42
ch.close
Buffered channels:
let ch: Channel[Integer] := create Channel[Integer].with_capacity(2)
ch.send(10)
ch.send(20)
print(ch.size) -- 2
Use select to wait on multiple operations:
select
when jobs.receive as job then
print(job)
when worker.await as value then
print(value)
timeout 1000 then
print("timed out")
else
print("idle")
end
class Pet
feature
name: String
sound: String
create
make(name: String, sound: String) do
this.name := name
this.sound := sound
end
feature
speak do
print(name + " says " + sound)
end
end
let cat: Pet := create Pet.make("Mimi", "meow")
cat.speak -- "Mimi says meow"
class Circle
create
make(r: Real) do
radius := r
end
feature
radius: Real
area(): Real do
result := 3.14159 * (radius ^ 2)
end
end
let c: Circle := create Circle.make(5.0)
print(c.area) -- 78.53975
class Animal
feature
name: String
speak do print(name) end
create
with_name(n: String) do name := n end
end
class Dog
inherit Animal
feature
speak do
print(name + " says Woof!")
end
create
with_name(n: String) do Animal.with_name(n) end
end
A field declared with once can be set in a constructor but never reassigned afterward. The typechecker enforces this at compile time.
class Point
feature
once x: Integer
once y: Integer
create
make(px: Integer, py: Integer) do
x := px
y := py
end
end
Assigning a once field outside a constructor is a compile-time error.
Tell Nex what must be true before, after, and always:
class Wallet
feature
money: Real
spend(amount: Real)
require -- must be true BEFORE
enough: amount <= money
do
money := money - amount
ensure -- must be true AFTER
less: money = old money - amount
end
invariant -- must ALWAYS be true
not_negative: money >= 0.0
end
let attempts: Integer := 0
do
attempts := attempts + 1
if attempts < 3 then
raise "not ready yet"
end
print("done on attempt " + attempts)
rescue
print("failed, trying again...")
retry -- jump back to do and try again
end
raise throws an error. rescue catches it. retry jumps back to the do block and runs it again from the top.
case direction of
"up" then print("going up")
"down" then print("going down")
else print("standing still")
end
A sealed deferred class closes its hierarchy — only its declared subclasses may extend it.
sealed deferred class Result
end
class Ok
inherit Result
feature value: Integer
create make(v: Integer) do value := v end
end
class Err
inherit Result
feature msg: String
create make(m: String) do msg := m end
end
let x: Integer := 10
do
let x: Integer := 99 -- shadows the outer x
print(x) -- 99
end
print(x) -- 10
convert <value> to <name>:<Type>
true if conversion succeeds, else false.<name> is bound to the converted value.<name> is bound to nil.if convert vehicle_1 to my_car:Car then
my_car.sound_horn
end
Dispatches on the runtime type of an expression. Against a sealed type, the typechecker verifies every variant is covered — a missing branch is a compile-time error.
match r of
when Ok as ok then
print(ok.value)
when Err as err then
print(err.msg)
end
An else branch covers remaining cases and suppresses the exhaustiveness check.
match r of
when Ok as ok then
print(ok.value)
else
print("not ok")
end
let add: Function := fn (a, b: Integer): Integer do result := a + b end
print(add(3, 4)) -- 7
class Box [T]
feature
value: T
create
make(v: T) do value := v end
end
let b: Box [Integer] := create Box[Integer].make(42)
b.value -- 42
Generic functions:
function first[T](values: Array[T]): T
do
result := values.get(0)
end
print(first([10, 20, 30])) -- 10
print(first(["a", "b", "c"])) -- "a"
x := 10 -- set an existing variable
let y: Integer := 20 -- create a new variable
this.name := "Nex" -- set a field inside a method