ferrule language specification
draftferrule language specification
this is the specification for ferrule α1. it describes what the language is and what it will be. each document has front matter that tells you what's implemented, what's planned, and what's been deferred to future versions.
the spec is the single source of truth. if something isn't in here, it's not part of the language yet.
how to read this
each document has yaml front matter at the top:
---
title: some feature
status: α1 # α1, α2, β, or rfc
implemented: # sections that work right now
- basic-stuff
- other-thing
pending: # sections planned for this phase
- advanced-stuff
deferred: # pushed to later phase or rfc
- complex-thing
---status meanings:
α1means it's part of the current milestoneα2means next milestoneβmeans laterrfcmeans it's a proposal, not committed
conventions:
codefor syntax and identifiers[link](path)references the canonical definition- examples are runnable unless marked otherwise
design pillars
these are the five ideas that guide every decision:
- regions are the memory model: every allocation lives in a region, no gc, no borrow checker. you choose the region, the compiler enforces lifetimes.
- effects are the control flow model: errors, async, generators, resource cleanup all unified under one mechanism.
fail<E>is just an effect.suspendis just an effect. no special syntax for any of them. - capabilities are the authority model: no ambient access, everything is passed. fs, net, clock, rng are values. the runtime is a record type that provides them.
- types carry meaning: nominal types, refinement types, effect-aware function types. two records with the same shape are not the same type. a
Portis not au16. - no magic: one way to do each thing, explicit over implicit, weakest mechanism that works. no macros. no implicit coercions. no hidden control flow.
what's in α1
the core language that you can actually use:
| feature | status |
|---|---|
| primitives (i8-i128, u8-u128, f32/f64, bool, char, string) | implemented |
| records and discriminated unions | implemented |
| pattern matching with exhaustiveness | implemented |
| basic generics (monomorphization) | partial |
effects (declaration, subset rule, fail<E>) | partial |
| regions (heap, arena, scope-bound) | planned |
| refinement types | planned |
| traits (record types + impl blocks) | planned |
| scope blocks (retry, timeout, transaction, parallel) | planned |
| opaque types | planned |
| move semantics | planned |
| capabilities (runtime record, with cap syntax) | planned |
| unsafe blocks | planned |
| basic stdlib (core, alloc) | partial |
what's deferred
these features are designed but not part of α1:
| feature | target | notes |
|---|---|---|
| views (fat pointers) | α2 | with escape analysis |
| capability attenuation | α2 | restrict, compose |
| comptime | α2 | compile-time evaluation |
| when blocks | α2 | conditional compilation |
| derive | α2 | automatic impl generation |
| tagged literals | α2 | custom literal syntax |
| test framework | α2 | test blocks, ferrule test |
| structured concurrency | β | task.scope, spawn, await |
| async (suspend effect) | β | effect-based, pluggable runtimes |
| hkt | rfc | higher-kinded types |
| mapped types | rfc | type transformation |
| conditional types | rfc | planned |
| variadic generics | rfc | planned |
looking for future features? check out the rfcs for proposed additions to the language.
specification index
core language
| document | scope |
|---|---|
| core/lexical | source encoding, identifiers, keywords, comments |
| core/types | scalars, compounds, unions, nominal typing, refinement types, opaque types |
| core/declarations | const, var, inout, move semantics |
| core/control-flow | if, match, for, while, break, continue, scope blocks |
| core/generics | type parameters, constraints |
| core/traits | record-based traits, impl blocks, derive |
functions and effects
| document | scope |
|---|---|
| functions/syntax | function declaration |
| functions/effects | effect system, standard effects, fail<E>, suspend, resource cleanup |
error handling
| document | scope |
|---|---|
| errors/domains | error types, domains as unions |
| errors/propagation | ok, err, check, ensure, fail |
memory model
| document | scope |
|---|---|
| memory/ownership | move semantics, copy vs move |
| memory/regions | region kinds, creation, disposal, lifetime enforcement |
| memory/views | view formation, slicing, bounds |
modules and capabilities
| document | scope |
|---|---|
| modules/packages | package structure, deps.fe |
| modules/imports | import syntax |
| modules/capabilities | capability parameters, runtime record, with cap syntax |
unsafe
| document | scope |
|---|---|
| unsafe/blocks | raw pointers, extern calls |
concurrency (β)
| document | scope |
|---|---|
| concurrency/tasks | task.scope, spawn, await |
| concurrency/determinism | test schedulers |
advanced (α2+)
| document | scope |
|---|---|
| advanced/comptime | comptime functions, reflection |
| advanced/metaprogramming | comptime, derive, when, tagged literals (no macros) |
| advanced/ffi | c abi, extern |
reference
| document | scope |
|---|---|
| reference/grammar | complete ebnf grammar |
| reference/keywords | reserved words |
| reference/stdlib | standard library: core, alloc, codec, io, framework |
key decisions
these are the choices that define ferrule:
| topic | decision |
|---|---|
| memory | regions are the allocation model, no gc, no borrow checker |
| equality | single == operator, no === |
| functions | function keyword for all, no arrows, no fn |
| errors | fail<E> effect, not a separate error E clause. errors are effects |
| traits | record types + impl blocks, no trait keyword |
| polymorphism | records + generics + impl, derive for boilerplate |
| capabilities | runtime is a record type providing caps, no ambient authority |
| effects | unified model: fail, suspend, resource cleanup all effects |
| refinement types | first-class in α1, not deferred |
| opaque types | encapsulation without exposing internals |
| scope blocks | retry, timeout, transaction, parallel. structured control flow |
| metaprogramming | comptime + derive + when + tagged literals, no macros |
| stdlib layers | core, alloc, codec, io, framework |
| runtime | no libc by default, raw syscalls, thin zig runtime |
| inference | unambiguous literals ok, boundaries need annotation |
| unsafe | blocks enable raw pointers/extern, don't disable other checks |
to be defined
these decisions are still open:
| topic | options |
|---|---|
| integer overflow | wrap in release, trap in debug (zig-style) |
| division by zero | trap |
| out of bounds | trap in debug, undefined in release |
| error recovery | how many errors before bail, cascading strategy |
language identity
ferrule is a systems language where regions, effects, and capabilities are first-class. you get low-level control with safety guarantees about what code can do, what memory it touches, and where allocations live, without a gc or a borrow checker.
target users:
- embedded developers who want more safety than c
- server developers who want more control than go
- security-critical systems where capability audit trails matter
- developers who want rust-style safety without fighting the borrow checker
what it's not:
- not rust (no borrow checker, regions instead, simpler generics)
- not zig (effects and capabilities are language features, not conventions)
- not go (no gc, explicit error handling, no ambient authority)