Comments
-- This is a comment. The computer ignores it.
-- Use comments to explain your code to other humans!
Values and Variables
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.

Printing
print("Hello, world!")
print(name)
print("I am " + age + " years old")
Math
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.

Comparing Things
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 identity
print([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
Choosing: if / then / else
if age >= 18 then
  print("You can vote!")
elseif age >= 13 then
  print("You are a teenager")
else
  print("You are a kid")
end
Inline Choice: when
let label: String := when age >= 18 "adult" else "minor" end
Loops: from / until
from let i: Integer := 1 until i > 5 do
  print(i)
  i := i + 1
end
-- prints 1 2 3 4 5
Repeat
repeat 3 do
  print("hello!")
end
-- prints hello! three times
Across

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
Functions
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
Arrays
let colors: Array [String] := ["red", "green", "blue"]
print(colors.get(0))            -- "red"
colors.add("yellow")            -- add to the end
print(colors.length)            -- 4
Maps
let pet: Map [String, String] := {"name": "Max", "kind": "dog"}
print(pet.get("name"))            -- "Max"
pet.put("kind", "cat")            -- update a value
Sets

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}
Concurrency: spawn, Task, and Channel

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
Classes
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
Creating Objects
let cat: Pet := create Pet.make("Mimi", "meow")
cat.speak                        -- "Mimi says meow"
Constructors
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
Inheritance
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
Once Fields

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.

Design by Contract

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
Error Handling
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 / Of
case direction of
  "up"    then print("going up")
  "down"  then print("going down")
  else         print("standing still")
end
Sealed Classes

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
Scoped Blocks
let x: Integer := 10
do
  let x: Integer := 99          -- shadows the outer x
  print(x)                      -- 99
end
print(x)                        -- 10
Type Conversion: convert
convert <value> to <name>:<Type>
  • Returns true if conversion succeeds, else false.
  • On success, <name> is bound to the converted value.
  • On failure, <name> is bound to nil.
if convert vehicle_1 to my_car:Car then
  my_car.sound_horn
end
Match Statement

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
Anonymous Functions
let add: Function := fn (a, b: Integer): Integer do result := a + b end
print(add(3, 4))                -- 7
Generics
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"
Assignment
x := 10                         -- set an existing variable
let y: Integer := 20            -- create a new variable
this.name := "Nex"              -- set a field inside a method