A curated list of some of Turmeric's best features
From algebraic effects to refinement types, each stop in this tour shows you real language features with real code.
Stick around to the end to learn how to install Turmeric in one step, no setup required.
01 -- Sweet-Exp Syntax
A single #lang declaration switches from Lisp-style parentheses to Sweet-Exp notation. It provides a less intimidating syntax, which is indentation-sensitive, with f(args) for inline calls, among other small enhancements, while being fully backwards-compatible.
Both syntaxes compile to the same AST. Sweet-Exp code and classic Turmeric code share libraries freely and can coexist in the same project, and other #langs and "language layers" may be released in the future.
02 -- Algebraic Effects
handle side-effects themselves.Your functions declare what side effects they may perform. Their callers decide how to handle them, depending on context. For example, let behavior change in tests, for mocking, or create wizard-like workflows where the consumer handles the in-between.
The type system ensures any effect that needs handling gets handled. Swap between handlers at the call site without touching the core logic.
03 -- Typeclasses
Typeclass dispatch resolves to a concrete instance at compile time, with no virtual tables, or additional runtime cost. Define a typeclass once and the compiler verifies every call site has a valid instance.
04 -- ADTs, GADTs & Pattern Matching
defdata declares sum types, while defgadt lets each constructor specialize its own type parameters. Every match arm refines what the checker knows. There's no casts, and there's no runtime tags.
Missing branches are caught at compile time. Every case is statically verified before the program runs.
05 -- Delimited Continuations
Turmeric reifies a slice of the call stack as an ordinary value. reset delimits the region and shift captures it.
Generators, async/await, and backtracking are all built on those two primitives.
06 -- Macro System
Macros in Turmeric operate directly on the syntax tree at compile time. New control flow, DSLs, and syntactic sugar are defined with defmacro, and a macro may generate any valid type-safe Turmeric code.
Quasiquote (`) and unquote (~) is a lightweight syntax that will hopefully feel familiar to Clojurians, at least.
07 -- Reference Counting
Turmeric uses reference counting with compiler-assisted elision. rc/clone increments, while rc/drop decrements. Cleanup is deterministic, and there are never any GC pauses or dangling pointers.
When the count hits zero, the value is freed right there, at that line. You can see exactly where memory is released.
08 -- Optional GC
Reference counting leaks cycles, and every RC language has this problem. Turmeric's answer is a Bacon-Rajan trial-deletion collector layered on top of RC, and it is off by default. Nothing traces, nothing pauses, until you ask.
Turn it on and you choose the trigger: (gc!) to collect right here, a suspect-count threshold, or fully automatic at allocation checkpoints. Only rc<T> values participate -- stack values, arenas, and by-value structs are never involved.
09 -- Higher-Order Functions
Functions are first-class values in Turmeric, and you can pass them, return them, store them, and compose them. Closures capture their lexical environment with full type inference.
The standard library's map, filter, and reduce work uniformly over any foldable structure, not just lists.
10 -- Refinement Types
#refine{ x : T | p } is a refinement type -- a value of type T that satisfies predicate p, checked automatically at compile-time (if possible). A parameter's predicate becomes a hypothesis, and a return type becomes a goal, so a bad argument is a compile error.
There is no external solver to install. The solver is built into compiler, so it works in the browser playground too.
11 -- Contract Types
The same #refine{...} predicate has a runtime meaning too. Name one with deftype, or declare invariants directly in the signature with :pre and :post, and the compiler inserts the checks for you.
The runtime meaning is what keeps the prover honest: it can give up on an obligation and stay sound, falling back to the check the value would have had anyway. Turning it on can never make a correct program wrong, and you can strip the checks from a release build with no code changes. Refinements and contracts are optional.
12 -- Spice -- Package Manager
One build.tur file describes your package and all its spices -- Turmeric fetches, builds, and links them automatically. Git URLs and version refs are all you need.
C and CMake dependencies go under :cmake-deps and are wired in automatically via CPM.cmake.
13 -- Structural Typing
(int | bool) is a structural union, for which the compiler generates exhaustiveness-checked dispatch for every member with no boxing or runtime overhead. Every union member must be handled.
The any top type enables gradual typing: every concrete type is a subtype of any. Inspect the tag at runtime with type-of. Both are built right into the language.
14 -- Trowel -- The Editor
Trowel is a fast, native desktop editor for Turmeric -- not Electron! -- with the compiler shipped inside the bundle. Open a file, press Run, see the output in the pane below. A live REPL sits in the split underneath your code.
Docstrings and completion for stdlib and buffer-local names come from the bundled compiler's own doc index, so they always match the compiler you are building with. Toggle between languages from the toolbar, or sccaffold a new project without touching the terminal.
Open the playground and try any of these features right in your browser -- or download Trowel and build them locally.