a systems language where effects and capabilities are first-class
α1
ferrule is a low-level systems language where you get zig-level control with safety guarantees about what code can do, not just what memory it touches.
- errors as values — no exceptions, typed error domains, lightweight propagation
- explicit effects — functions declare what they can do (
fs,net,time, etc.) - scoped ownership — move semantics without a borrow checker
- capability security — no ambient authority; permissions are values you pass
- strict nominal types — no accidental structural compatibility
error NotFound { path: Path }
error Denied { path: Path }
type IoError = NotFound | Denied;
function readConfig(path: Path, cap fs: Fs) -> Config error IoError effects [fs] {
const data = check fs.readAll(path);
return ok parse(data);
}
# create a new project
ferrule new my-app
cd my-app
# build and run
ferrule build
ferrule run| document | description |
|---|---|
| language specification | complete language reference |
| package management | manifests, lockfiles, cli |
core language
- lexical structure — encoding, identifiers, keywords
- types — scalars, unions, nominal typing
- declarations —
const,var,inout, move semantics - control flow —
if,match, loops - generics — type parameters, constraints
functions and effects
- function syntax —
functionkeyword for all - effects — effect system, subset rule
error handling
- error domains — standalone errors, domains as unions
- propagation —
check,ensure
memory
- ownership — move semantics, copy vs move
- regions — allocation, disposal (α2)
- views — fat pointers, slicing (α2)
modules
- packages — deps.fe, project structure
- imports — resolution, visibility
- capabilities —
with capsyntax, linear types
unsafe
- unsafe blocks — raw pointers, extern calls
reference
- grammar — ebnf
- keywords — reserved words
- operators — precedence (
==not===) - stdlib — standard library
- immutability first —
constby default - errors as values — no exceptions
- explicit effects — functions declare what they do
- scoped ownership — move semantics, no borrow checker
- capability security — no ambient authority
- strict nominal types — no structural compatibility
- no implicit coercions — explicit always
- explicit polymorphism — records + generics, no traits
package my.app;
import std.io { println };
error Timeout { ms: u64 }
error Network { message: String }
type AppError = Timeout | Network;
function main(args: Args) -> i32
with cap io: Io, cap net: Net, cap clock: Clock
{
const deadline = clock.now() + Duration.seconds(30);
match fetchWithRetry("https://api.example.com", deadline, net, clock) {
ok resp => {
println(resp.body, io);
return 0;
},
err e => {
println("request failed", io);
return 1;
}
}
}
function fetchWithRetry(
url: String,
deadline: Time,
cap net: Net,
cap clock: Clock
) -> Response error AppError effects [net, time] {
var attempts: u32 = 0;
while attempts < 3 {
match net.get(url) {
ok resp => return ok resp,
err e => {
attempts = attempts + 1;
if attempts < 3 {
clock.sleep(Duration.seconds(1));
}
}
}
}
return err Timeout { ms: 30000 };
}
α1 — language design is stabilizing. core features working, many planned features not yet implemented.
see the specification for what's implemented vs planned.