Low
A compiled, garbage-collected language with green threads, enums and typed errors. It builds small static binaries for Linux and Windows.
enum Shape {
Circle(radius: i64)
Rect(w: i64, h: i64)
}
fn area(s: Shape) -> i64 {
match s {
Circle(r) => 3 * r * r
Rect(w, h) => w * h
}
}
fn main() {
print(area(Shape.Rect(3, 4)))
}
Install
Linux
$ curl -fsSL https://low.simoncurtis.dev/install.sh | shWindows
> irm https://low.simoncurtis.dev/install.ps1 | iexNeeds binutils for as and ld. The Windows target also needs clang and lld-link. Build from source
Use
$ cat hello.low
fn main() {
print("hello")
}
$ low run hello.low
hello
$ low build hello.low -o hello
$ low build hello.low -target windows/amd64
Compile-time checks
enum Shape {
Circle(radius: i64)
Rect(w: i64, h: i64)
Empty
}
fn area(s: Shape) -> i64 {
match s {
Circle(r) => 3 * r * r
Rect(w, h) => w * h
}
}
fn main() {
print(area(Shape.Empty))
}
shape.low:8:5: missing arms for Empty
enum MathError {
DivideByZero
}
fn divide(a: i64, b: i64) -> i64 ! MathError {
if b == 0 { fail DivideByZero }
a / b
}
fn main() {
print(divide(7, 0))
}
math.low:11:11: unhandled error MathError: use ? or catch
Benchmarks against Go
| Low | Go | |
|---|---|---|
| Binary | 32 KB | 2.3 MB |
| Build | 18 ms | 122 ms |
| Run | 149 ms | 163 ms |
The fib benchmark, median of three runs. Across nine benchmarks Low runs in 0.44 to 0.98 times Go's time and uses more peak memory on six.
Compilation stages
Source
fn fib(n: i64) -> i64 {
if n < 2 { n } else {
fib(n - 1) + fib(n - 2)
}
}
IR
fn fib params=1 results=1 slots=[]
b0: preds=[]
v1 = param #0 []
v2 = const #2 []
v3 = lt:i64 [v1 v2]
if v3 then b1 else b2
b1: preds=[b0]
jump b3
Assembly
fn_fib:
.Lfib_0:
cmp rdi, 2
jge .Lfib_2
.Lfib_1:
mov rax, rdi
ret
Binary
7f45 4c46 0201 0100
0000 0000 0000 0000
0200 3e00 0100 0000
ba47 4000 0000 0000
4000 0000 0000 0000
787e 0000 0000 0000
Runtime and standard library
fn worker(jobs: chan[i64], results: chan[i64]) {
for j in jobs { results <- j * j }
}
fn main() {
let jobs = chan[i64](16)
let results = chan[i64](16)
for _ in 0..4 { spawn worker(jobs, results) }
for i in 1..11 { jobs <- i }
close(jobs)
var total = 0
for _ in 0..10 { total += (<-results) ?? 0 }
print(total)
}
- Green threads on every core.
- Typed channels.
- A tracing collector.
- Hot reload on Linux.
- HTTP, TLS, SQL and JSON.
- VS Code, Zed and Neovim.
- Linux and Windows.