-- 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 examples:
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 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
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 and define the bodies afterwards:
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
The later definition must match the earlier declaration exactly.
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] := #{}
You can also build a set from an array. Duplicate elements are removed:
let numbers: Set[Integer] := create Set[Integer].from_array([1, 2, 2, 3])
print(numbers.size) -- 3
Sets support the usual 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 (after completion)
If the spawn body does not assign result, the type is
plain Task:
let t: Task := spawn do
print("background work")
end
Task operations: - await waits until the task finishes -
await(ms) waits up to ms milliseconds and
returns nil on timeout - cancel requests task
cancellation and returns true if the task was cancelled
before finishing - is_done reports whether the task has
finished - is_cancelled reports whether the task was
cancelled - await_any([t1, t2, ...]) waits for the first
task to finish and returns its result -
await_all([t1, t2, ...]) waits for all tasks and returns an
array of results
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
print(ch.is_closed) -- true
Use .with_capacity(n) for buffered channels:
let ch: Channel[Integer] := create Channel[Integer].with_capacity(2)
ch.send(10)
ch.send(20)
print(ch.size) -- 2
print(ch.capacity) -- 2
Channel operations: - send(value) blocks until accepted
- send(value, ms) waits up to ms milliseconds
and returns true on success, false on timeout
- receive blocks until a value is available -
receive(ms) waits up to ms milliseconds and
returns nil on timeout - try_send(value)
returns true if the send succeeds immediately, otherwise
false - try_receive returns a value if one is
immediately available, otherwise nil - close
prevents future sends; buffered values may still be received -
is_closed, size, and capacity
report channel state
Use select to wait on multiple channel operations or
completed tasks:
select
when jobs.receive as job then
print(job)
when worker.await as value then
print(value)
when control.receive as signal then
print(signal)
timeout 1000 then
print("timed out")
else
print("idle")
end
select probes its clauses using try_send /
try_receive for channels and is_done for
tasks. Task clauses must use Task.await; they fire only
when the task has already completed. If no clause is ready and there is
no else, select waits until one becomes
ready.
JavaScript target note: - generated JavaScript uses Promise-based
semantics - Nex source syntax stays the same - spawn lowers
to async task code - Task.await, Channel.send,
and Channel.receive lower to await ... in
generated JavaScript
For full concurrency semantics and runtime details, see CONCURRENCY.md.
A class bundles data and actions together:
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"
A constructor sets up an object when it is created:
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
A class can build on another class:
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
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
(the value is in exception). 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
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.<Type> must be a supertype or subtype of the runtime
type of <value>.do
convert vehicle_1 to my_car:Car
-- my_car is visible in this block
end
if convert vehicle_1 to my_car:Car then
my_car.sound_horn
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
x := 10 -- set an existing variable
let y: Integer := 20 -- create a new variable
this.name := "Nex" -- set a field inside a method
Nex reads like English: if...then...end,
from...until...do...end, repeat...do...end,
across...as...do...end, class...feature...end.
Write what you mean, and Nex will check that you mean what you
write.