Skip to content

Overview and philosophy

dusk is a small systems language that compiles to native code through textual LLVM IR. Every file picks a paradigm with @paradigm procedural, functional, or oop, and that choice unlocks the matching builtins. Values are immutable by default, memory is explicit, and errors are values you handle.

This page lays out the philosophy that the rest of the reference builds on. The reference describes the 0.1.0 core with the changes the 0.2.x and 0.3.x releases layered on top; each page notes where the current language differs from the baseline.

The specification opens with six commitments, and the checker holds the line they draw.

  • Immutability by default. All values are immutable unless explicitly declared mutable with mut. Immutability covers element and field stores, not just rebinding.
  • Explicit over implicit. Allocations, dereferences, paradigm usage, and error handling are never hidden.
  • Multiple paradigms with enforced discipline. Paradigms are opt in per file through directives. Using a paradigm feature the file has not declared is a compile error in that file. See Paradigm system.
  • Systems level control. Manual memory management by default. No garbage collector unless explicitly opted into through the standard library.
  • All declared variables must be used. An unused variable is a compile error. This is never suppressible.
  • All errors must be handled. Ignoring an error return is a compile error. See Error handling.

A small complete program shows several of these at once: the file declares the functional paradigm before it may call map and foreach, every binding is immutable, and every binding is used.

overview-taste.dusk
@paradigm functional
func main() -> int32 {
nums: int64[] = [1, 2, 3, 4, 5]
doubled := map(nums, lambda (n: int64) -> int64 { return n * 2 })
foreach(doubled, lambda (n: int64) -> void { println(n) })
return 0
}

The static checker holds the line the spec draws:

  • Integer and float widths never mix silently.
  • Immutability extends to element and field stores.
  • Every array index and range slice is bounds checked, and a bound error must be handled.
  • An allocation is sized by its declared type.
  • Printing dispatches through Display or fails to compile.
  • A private name never leaves its file.

Beyond the static checks, the default heap since 0.2.x is generational: every managed pointer carries a generation that is checked at each dereference, so a use after free, a double free, or a stale pointer to a reused block faults instead of corrupting memory. See Memory management for the managed and raw pointer split.

The compiler is written in Rust with zero dependencies. It runs the whole pipeline itself: it lexes, parses, resolves names, type checks, monomorphizes, and emits textual LLVM IR. The IR is handed to clang for native code generation, and each program links against a small C runtime.

Two consequences follow from this design:

  • Building dusk programs requires clang and LLVM on your path. The textual IR targets one LLVM major version; as of 0.3.3 that is LLVM 22.x.
  • The compiler binary itself needs nothing beyond the Rust standard library to build.

The compiler finds its standard library and C runtime beside itself. The DUSK_HOME environment variable overrides the search when you want a binary to use a different toolchain tree, such as a source checkout. The standard library under lib/std is written in dusk itself; see the standard library overview.

The dusk binary exposes each pipeline stage as a command (lex, scan, parse, check, build, run, demo, version); see the CLI reference. Dawn is the accompanying package tool, which treats a package as a git repository; see Dawn and Packages.

The current release is 0.3.3. The language is pre 1.0, and every minor release changes it, so installing today means tracking a moving target. The CHANGELOG records the release by release history; in outline:

  • 0.1.0 is the core language the specification describes.
  • 0.2.0 through 0.2.6 add memory safety: the StringBuilder, the split between managed *T and raw *raw T pointers, the generational heap, single ownership with ref and move, escape checking for the clear cases, and foreign "C" calls into libc across the raw pointer boundary.
  • 0.3.0 through 0.3.3 add concurrency: spawn and join for OS threads, thread safe generational checking, atomics, channels with blocking and non-blocking operations, mutexes and condition variables that fault by name on classic pthread misuse, and a global thread pool with the submit builtin. See Threads and the memory model.

The 0.4.x releases build the async layer on this substrate; see the roadmap.

Where this reference describes 0.1.0 behavior that a later release changed (immutable-only strings, a single pointer kind, debug-only memory safety), the affected page carries a version caveat.