Write code that keeps its promises with Nex

Learn to program, and to engineer software properly. Nex is a small language built for teaching: you state what your code promises, and Nex checks it. Free books take you from your first program to designing real systems.

3 free books open source (MPL-2.0) v0.6.0

wallet.nex
class Wallet
feature
  money: Real

  spend(amount: Real)
  require
    enough: amount <= money
  do
    this.money := money - amount
  ensure
    decreased: money = old money - amount
  end
create
  with_balance(amount: Real) do
    money := amount
  end
end

let w := create Wallet.with_balance(10.2)
w.spend(20.0)
Error: Precondition violation: enough
// why nex

Small on purpose.

Big in expressive power: contracts, readable syntax, objects, functions and the JVM, all in one compact design. Pick a tab to see each in action.

State what must be true. Nex checks it, and names the exact promise that was broken.

no contractsilent
spend(amount: Real)
do
  this.money := money - amount
end
REPL
> w.spend(20.0)
> w.money
-9.8   -- negative balance… and nobody noticed
with requireguarded
spend(amount: Real)
require
  non_negative_amount: amount >= 0.0
  enough: amount <= money
do
  this.money := money - amount
ensure
  decreased: money = old money - amount
end
REPL
> w.spend(20.0)
Error: Precondition violation: enough
class invariantalways true
invariant
  never_negative: money >= 0.0
end
REPL
> create Wallet.with_balance(-10.0)
Error: Class invariant violation: never_negative

Words instead of punctuation. Blocks open and close with plain keywords, so code reads close to how you would say it.

decide.nex
let age := 12

if age >= 18 then
  print("adult")
elseif age >= 13 then
  print("teen")
else
  print("child")
end
output
child
repeat.nex
across [10, 20, 30] as x do
  print(x)
end

repeat 3 do
  print("tick")
end
output
10
20
30
tick
tick
tick
choose.nex
let category := when age >= 18
  then "adult"
  else "minor"
end

case age of
  0, 1, 2 then print("small")
  3, 4, 5 then print("medium")
  else print("large")
end
REPL
> category
"minor"
large
-- when is an expression; case picks a branch

Classes and inheritance sit beside first-class functions, so you can pick the right tool for each problem.

counter.nex
class Counter
create
  make(start: Integer) do
    this.value := start
  end
feature
  value: Integer
  inc() do
    this.value := this.value + 1
  end
  current(): Integer do
    result := value
  end
end
REPL
> let c: Counter := create Counter.make(10)
> c.inc
> print(c.current)
11
animals.nex
class Animal
feature
  name: String
  speak do print(name) end
create
  named(name: String) do
    this.name := name
  end
end

class Dog
  inherit Animal
feature
  speak do
    print(name + " says woof")
  end
end
REPL
> let a: Animal := create Animal.named("Ko")
> a.speak
Ko
> let d: Animal := create Dog.named("Ki")
> d.speak
Ki says woof
functions.nex
function double(n: Integer): Integer
do
  result := n * 2
end

-- anonymous functions
let inc := fn (n: Integer): Integer do
  result := n + 1
end
REPL
> print(double(5))
10
> print(inc(10))
11

Nex compiles to JVM bytecode and can call any Java library. Ship one jar that runs anywhere Java does.

line_buffer.nex
import java.lang.StringBuilder

class Line_Buffer
create
  make() do
    with "java" do
      this.builder := create StringBuilder
    end
  end
feature
  builder: Any
  append_line(s: String) do
    with "java" do
      builder.append(s)
      builder.append("\n")
    end
  end
end
notes
-- import names a Java class
-- with "java" do … end runs host calls
--
-- keep host types behind a small Nex class,
-- so the rest of the program depends on a
-- clear contract, not on Java details.
script.nex
print("Hello from the JVM")
terminalstandalone jar
$ nex compile jvm script.nex ./build
# writes ./build/script.jar
terminal
$ java -jar ./build/script.jar
Hello from the JVM
notes
-- copy the jar to any machine with a JVM.
-- no Nex runtime needed there.
// learn nex

From "hello" to real systems.

Free and online. Pick the road that fits where you are today.

Reference
// for teachers

Teaching programming or software engineering?

Two free companion books cover an introductory course and a software-engineering course. Contracts, invariants and tests are part of the language, so correctness is taught from the first week rather than bolted on at the end.

Using Nex in a course, or thinking about it? I'd like to hear what you need. Get in touch.

  • Programming with Nex: 29 chapters, from first programs through classes, contracts and testing
  • Exercises throughout, with worked solutions to selected ones
  • Beyond Code: 36 chapters on decomposition, interfaces, invariants and specification
  • 6 hands-on studios and 2 algorithm labs
  • Everything free to read online; Nex itself is open source
// get started

Install in one line.

Linux and macOS (on Windows, use WSL with Ubuntu). Then run nex to open the REPL.

Quick install

Installs the nex command system-wide, with REPL, formatter, docs and compiler tools. If they're missing, it also installs Java and the Clojure CLI, so it asks for your administrator password. It compiles Nex as it goes, which takes a minute or two.

bash <(curl -fsSL https://raw.githubusercontent.com/vijaymathew/nex/main/bootstrap-install.sh) jvm --install-deps
Without sudo

User-local install under ~/.local. Needs Java 17 or later already installed (ask an administrator); the installer fetches everything else. Open a new terminal afterwards so nex is on your PATH.

bash <(curl -fsSL https://raw.githubusercontent.com/vijaymathew/nex/main/bootstrap-install.sh) jvm --prefix "$HOME/.local" --install-deps
Editor support

An Emacs major mode ships in editor/emacs/nex-mode.el, with highlighting, indentation, Imenu and REPL integration (setup guide ↗). Support for other editors is planned.

Stuck, or have a question?

Ask in GitHub Discussions ↗. No question is too basic: installing, an error you don't understand, or an exercise from one of the books. The full install guide ↗ covers supported systems, uninstalling and troubleshooting.