GitHub

A memory-safe compiled language whose programs give the same results on every machine.

Calx is pre-release, and you build it from source. It runs on Windows and Linux.

Parallel loops are checked when you compile

parallel for runs a loop's iterations on a pool of threads. The compiler rejects a loop in which one iteration changes data that another one uses, so the output doesn't depend on the number of threads.

Changing a variable that every iteration shares is an error:
main.calx:6:9: error: `total` is shared by every iteration of the `parallel for`, so it can't be changed here; an iteration can change only its own elements, indexed with `k` itself
          total += xs[k]
          ^~~~~
1 error
game.calx
Tested
struct Region {
blocks: List<i32>,
total: i64,
}
fn tick(r: mut Region, scale: i32) {
for i in 0usize..r.blocks.len() {
r.blocks[i] = r.blocks[i] * scale + 1
r.total += i64(r.blocks[i])
}
}
fn main() {
var regions = List<Region>()
for k in 0..16 {
regions.push(Region { blocks: [k, k + 1, k + 2], total: 0 })
}
let scale = 3
parallel for k in 0usize..regions.len() {
tick(mut regions[k], scale)
}
println("{regions[0].total} {regions[15].total}")
}

What else it promises

Deterministic math

Integer and float arithmetic gives the same bits on every platform, and floats print the same way too. The rules are Java's.

fn main() {
let zero = 0.0
println("{0.1 + 0.2} {100.0} {1.0e7} {0.001} {1.0e-4}")
println("{-zero} {1.0 / zero} {zero / zero}")
println("{1.0f32 / 3.0f32} {f64(0.1f32)}")
}
0.30000000000000004 100.0 1.0E7 0.001 1.0E-4
-0.0 Infinity NaN
0.33333334 0.10000000149011612
Floats

Memory-safe without a garbage collector

Every value has one owner, and the compiler frees it where the owner ends. Using a value after it has moved is an error.

fn main() {
let a = String("x")
let b = a
println("{a} {b}")
}
error: `a` was moved, so it can't be used here
Ownership

Strict by default

There are no warnings. Unused values, shadowing and silent conversions are errors, and no flag turns one off.

fn three() -> i32 {
return 3
}
fn main() {
three()
_ = three()
}
error: this `i32` value is unused; discard it with `_ = ...`
Strictness

Fast to build

CI times the compiler on every push, on the same machine as the benchmark below.

WindowsLinux
calx check, 64 modules (9,900 lines)32 ms24 ms
Debug build of those 64 modules, empty cache520 ms278 ms
Debug rebuild after changing one module123 ms78 ms
calx run of a small program, empty cache274 ms302 ms
calx run of it again, nothing changed16 ms21 ms
The calx command

Faster than Rust, on our benchmark

We wrote the same simulation in Calx and in Rust, with the same algorithms. Both must produce the same checksum, and CI runs them on every push.

Milliseconds per ticklower is better
Calx, clang 23Rust, rustc 1.91.1

1 worker

One thread runs the whole tick
Windows 11
18.06 ms · 0.70×
25.75 ms
Linux (WSL2)
18.01 ms · 0.69×
26.04 ms

24 workers

Regions spread across every core
Windows 11
2.25 ms · 0.66×
3.41 ms
Linux (WSL2)
2.46 ms · 0.70×
3.52 ms
Median of 10 runs of 1,000 ticks on an i9-13900K. Method and raw results
Show as a table
PlatformCalx, 1 workerRust, 1 workerCalx, 24 workersRust, 24 workers
Windows 1118.0625.752.253.41
Linux (WSL2)18.0126.042.463.52

Learn it by building one program

The guide builds stash, a small program that keeps an inventory. Each page adds to it.

Input
add stone 64
add stone 66
take stone 5
take dirt 20
show
Output
line 4: there's no dirt
stone: 1 stack and 61
  1. Install Calx
  2. Getting started
  3. Reading the commands
  4. What the commands mean
  5. The stash

Built with Calx: Calcite

Calcite is a Minecraft Java Edition server, and the largest program written in Calx so far. It's still in development. The official client can log in, walk around a flat world and chat.