Skip to content

rendro/silt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

502 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

silt

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

import list

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)) }
}

Pattern matching

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

type Shape { Circle(Int), Square(Int), Triangle(Int, Int) }

fn area(s: Shape) -> Int {
  match s {
    Circle(r) -> 3 * r * r
    Square(w) -> w * w
    Triangle(b, h) -> b * h / 2
  }
}

Parallelism

Spawn lightweight tasks that run in parallel on a fixed thread pool. Communicate through channels. Every value is immutable, so there are no data races to debug. I/O operations transparently yield to the scheduler — no async/await needed.

import channel
import list
import task

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)
}

Errors as values

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

import io
import json

type Config { name: String }

fn main() {
  match io.read_file("settings.json") {
    Ok(content) -> match json.parse(content, Config) {
      Ok(cfg) -> println("loaded: {cfg.name}")
      Err(e) -> println("parse error: {e.message()}")
    }
    Err(IoNotFound(path)) -> println("no config at {path} — run `silt init` first")
    Err(e) -> println("read error: {e.message()}")
  }
}

Stdlib errors are typed enums — IoError, JsonError, HttpError, and so on — so match can fork on specific failures like IoNotFound(path) and still fall back to .message() for the long tail.

HTTP

Built-in HTTP client and server. Pattern matching replaces routing frameworks. Requests are handled concurrently.

import http
import json

type Todo { id: Int, title: String, done: Bool }

fn main() {
  http.serve(8080, fn(req) {
    match (req.method, http.segments(req.path)) {
      (GET, ["todos"]) -> {
        let todos = [
          Todo { id: 1, title: "Learn silt", done: true },
          Todo { id: 2, title: "Build an API", done: false },
        ]
        Response { status: 200, body: json.stringify(todos), headers: #{} }
      }
      (POST, ["todos"]) ->
        match json.parse(req.body, Todo) {
          Ok(todo) -> Response { status: 201, body: json.stringify(todo), headers: #{} }
          Err(e) -> Response { status: 400, body: e.message(), headers: #{} }
        }
      _ ->
        Response { status: 404, body: "Not found", headers: #{} }
    }
  })
}

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
}

Install

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

The installer verifies the downloaded binary against the release's SHA256SUMS file before extracting — a mismatch aborts the install so a corrupted or tampered archive can't land on disk. To upgrade an existing install without re-running the curl pipe, use silt self-update (which performs the same verification).

Or build from source:

git clone https://github.com/rendro/silt.git
cd silt && cargo build --release
cp target/release/silt ~/.local/bin/

Then:

silt init
silt run

silt init writes a silt.toml manifest and a starter src/main.silt; silt run (no arguments, inside a package) executes the entry point.

See examples/ for runnable sample programs — start with examples/hello.silt, examples/fizzbuzz.silt, and examples/records.silt.

Tooling

silt run <file.silt>       Run a program
silt run -w <file.silt>    Run and re-run on file changes
silt check <file.silt>     Type-check without running
silt check --format json <file.silt>   Type-check with JSON output (for CI/editors)
silt test [path]           Run test functions
silt fmt [files...]        Format source code
silt fmt --check           Check formatting without modifying files
silt repl                  Interactive REPL
silt init                  Create a new silt package in the current directory
silt lsp                   Start the language server
silt disasm <file.silt>    Show bytecode disassembly (same as `silt run --disassemble`)
silt self-update           Update the silt binary to the latest release
silt update [<dep-name>]   Regenerate silt.lock for the current package's dependencies
silt add <name> --path <path>                             Add a path-based dependency to silt.toml
silt add <name> --git <url> [--rev|--branch|--tag <ref>]  Add a git-based dependency to silt.toml

The --watch / -w flag works with run, check, and test. It watches the project directory for .silt file changes and automatically re-runs the command.

LSP server with diagnostics, hover types, go-to-definition, completion, signature help, document symbols, and formatting. The prebuilt silt binary from the install script includes the LSP server — just run silt lsp and point your editor at it. Vim/Neovim syntax highlighting and editor setup ship in editors/.

Reference

Feature Details
keywords as else fn import let loop match mod pub return trait type when where
types inferred, with ADTs, records, and traits
literals 42, 0xFF, 0b1010, 1e5, 1_000, "hi {x}"
branching match only
mutability none
errors Result / Option / ?
concurrency CSP with real parallelism
collections [1, 2, 3] list, #{"k": "v"} map, #[1, 2] set
stdlib small but exhaustive
tools REPL, formatter, test runner, LSP

Documentation

New here? Read Why silt to see how it compares to Rust, Go, Gleam, and OCaml. Then start with Getting Started to install silt and walk through the essentials, and see the Language Guide for the complete reference and the Standard Library for every built-in.

Deeper dives: Concurrency, FFI (embedding silt in Rust), and Editor Setup.

A hosted version with an interactive playground is at silt-lang.com.

License

MIT

About

A minimal, statically-typed, expression-based language with CSP concurrency

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages