silt

A delightful language for programmers who've suffered enough. Types without annotations. Threads without locks. Errors without surprises.

fn fizzbuzz(n) {
  match (n % 3, n % 5) {
    (0, 0) -> "FizzBuzz"
    (0, _) -> "Fizz"
    (_, 0) -> "Buzz"
    _ -> "{n}"
  }
}

fn main() {
  1..21
  |> list.each { n -> println(fizzbuzz(n)) }
}
get started → playground source

Install

curl -fsSL https://silt-lang.com/install.sh | sh
copied
01

Pattern matching

The only way to branch. Define your types, then match on their shape. The compiler verifies every case is handled.

type Expr {
  Num(Int),
  Add(Expr, Expr),
  Mul(Expr, Expr)
}

fn eval(expr) {
  match expr {
    Num(n) -> n
    Add(a, b) -> eval(a) + eval(b)
    Mul(a, b) -> eval(a) * eval(b)
  }
}
02

Parallelism

Spawn tasks on real OS threads. Communicate through channels. Every value is immutable, so there are no data races to debug.

fn main() {
  let ch = channel.new(10)

  let w1 = task.spawn(fn() {
    channel.each(ch) { msg -> println("w1: {msg}") }
  })
  let w2 = task.spawn(fn() {
    channel.each(ch) { msg -> println("w2: {msg}") }
  })

  list.each(1..100) { n -> channel.send(ch, n) }
  channel.close(ch)

  task.join(w1)
  task.join(w2)
}
03

Errors as values

Every function that can fail returns a Result. The ? operator propagates errors without nesting. Nothing is thrown or caught.

fn read_config(path) {
  let content = io.read_file(path)?
  let config = json.parse(Config, content)?
  Ok(config)
}

fn main() {
  match read_config("settings.json") {
    Ok(cfg) -> println("loaded: {cfg.name}")
    Err(e) -> println("error: {e}")
  }
}
04

Type inference

The type checker infers everything. You get static type safety without writing annotations. Define records, enums, and traits when you need structure.

type User {
  name: String,
  age: Int,
}

fn greet(user) {
  "hello, {user.name} ({user.age})"
}

fn main() {
  let u = User { name: "alice", age: 30 }
  println(greet(u))
  println(greet(u.{ age: 31 }))  -- record update
}

Reference

keywordsas else fn import let loop match mod pub return trait type when where
typesinferred, with ADTs, records, and traits
branchingmatch only
mutabilitynone
errorsResult / Option / ?
concurrencyCSP on OS threads
collections[1, 2, 3] list, #{"k": "v"} map, #[1, 2] set
stdlibsmall but exhaustive
toolsREPL, formatter, test runner, LSP
full guide →