ferrule

ferrule language specification

draft

ferrule 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:

  • α1 means it's part of the current milestone
  • α2 means next milestone
  • β means later
  • rfc means it's a proposal, not committed

conventions:

  • code for 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:

  1. regions are the memory model: every allocation lives in a region, no gc, no borrow checker. you choose the region, the compiler enforces lifetimes.
  2. effects are the control flow model: errors, async, generators, resource cleanup all unified under one mechanism. fail<E> is just an effect. suspend is just an effect. no special syntax for any of them.
  3. 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.
  4. types carry meaning: nominal types, refinement types, effect-aware function types. two records with the same shape are not the same type. a Port is not a u16.
  5. 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:

featurestatus
primitives (i8-i128, u8-u128, f32/f64, bool, char, string)implemented
records and discriminated unionsimplemented
pattern matching with exhaustivenessimplemented
basic generics (monomorphization)partial
effects (declaration, subset rule, fail<E>)partial
regions (heap, arena, scope-bound)planned
refinement typesplanned
traits (record types + impl blocks)planned
scope blocks (retry, timeout, transaction, parallel)planned
opaque typesplanned
move semanticsplanned
capabilities (runtime record, with cap syntax)planned
unsafe blocksplanned
basic stdlib (core, alloc)partial

what's deferred

these features are designed but not part of α1:

featuretargetnotes
views (fat pointers)α2with escape analysis
capability attenuationα2restrict, compose
comptimeα2compile-time evaluation
when blocksα2conditional compilation
deriveα2automatic impl generation
tagged literalsα2custom literal syntax
test frameworkα2test blocks, ferrule test
structured concurrencyβtask.scope, spawn, await
async (suspend effect)βeffect-based, pluggable runtimes
hktrfchigher-kinded types
mapped typesrfctype transformation
conditional typesrfcplanned
variadic genericsrfcplanned

looking for future features? check out the rfcs for proposed additions to the language.

specification index

core language

documentscope
core/lexicalsource encoding, identifiers, keywords, comments
core/typesscalars, compounds, unions, nominal typing, refinement types, opaque types
core/declarationsconst, var, inout, move semantics
core/control-flowif, match, for, while, break, continue, scope blocks
core/genericstype parameters, constraints
core/traitsrecord-based traits, impl blocks, derive

functions and effects

documentscope
functions/syntaxfunction declaration
functions/effectseffect system, standard effects, fail<E>, suspend, resource cleanup

error handling

documentscope
errors/domainserror types, domains as unions
errors/propagationok, err, check, ensure, fail

memory model

documentscope
memory/ownershipmove semantics, copy vs move
memory/regionsregion kinds, creation, disposal, lifetime enforcement
memory/viewsview formation, slicing, bounds

modules and capabilities

documentscope
modules/packagespackage structure, deps.fe
modules/importsimport syntax
modules/capabilitiescapability parameters, runtime record, with cap syntax

unsafe

documentscope
unsafe/blocksraw pointers, extern calls

concurrency (β)

documentscope
concurrency/taskstask.scope, spawn, await
concurrency/determinismtest schedulers

advanced (α2+)

documentscope
advanced/comptimecomptime functions, reflection
advanced/metaprogrammingcomptime, derive, when, tagged literals (no macros)
advanced/ffic abi, extern

reference

documentscope
reference/grammarcomplete ebnf grammar
reference/keywordsreserved words
reference/stdlibstandard library: core, alloc, codec, io, framework

key decisions

these are the choices that define ferrule:

topicdecision
memoryregions are the allocation model, no gc, no borrow checker
equalitysingle == operator, no ===
functionsfunction keyword for all, no arrows, no fn
errorsfail<E> effect, not a separate error E clause. errors are effects
traitsrecord types + impl blocks, no trait keyword
polymorphismrecords + generics + impl, derive for boilerplate
capabilitiesruntime is a record type providing caps, no ambient authority
effectsunified model: fail, suspend, resource cleanup all effects
refinement typesfirst-class in α1, not deferred
opaque typesencapsulation without exposing internals
scope blocksretry, timeout, transaction, parallel. structured control flow
metaprogrammingcomptime + derive + when + tagged literals, no macros
stdlib layerscore, alloc, codec, io, framework
runtimeno libc by default, raw syscalls, thin zig runtime
inferenceunambiguous literals ok, boundaries need annotation
unsafeblocks enable raw pointers/extern, don't disable other checks

to be defined

these decisions are still open:

topicoptions
integer overflowwrap in release, trap in debug (zig-style)
division by zerotrap
out of boundstrap in debug, undefined in release
error recoveryhow 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)

On this page