Alef Language Specification

This is the public specification for Alef source programs. It describes the language contract a user can rely on when writing .alef files. It is not a description of the private compiler or native runtime implementation.

The specification is intentionally stricter than the tutorial pages. Tutorials teach the path. This document defines the surface.

Source Files

Alef source files use the .alef extension.

A source file contains zero or more imports and declarations. Executable programs normally define main.

import std.http { json_response }

fn main() {
    println("hello")
}

Notation

Examples in this document use ordinary Alef source. Grammar fragments are written informally until the language grammar is published as a machine-readable artifact.

Names in code are literal tokens or language constructs.

Lexical Elements

Alef programs are written as Unicode text.

Whitespace separates tokens and is otherwise insignificant outside strings. Newlines are accepted between statements and declarations. Semicolons are not required in the beginner-facing style used by this book.

Comments

Line comments begin with // and continue to the end of the line.

// This is a comment.
println("ready")

Identifiers

Identifiers name values, functions, parameters, struct fields, enum variants, and imported bindings.

let ticket_id = "TD-101"
fn priority(plan, blocked) { ... }

Public examples should prefer readable names over abbreviations.

Keywords

The core keywords used in this book are:

fn let return if else for in while match struct enum import true false none
and or not

Standard-library names such as std.http are not keywords.

Literals

Alef supports:

Strings

Strings use double quotes.

let name = "Ada"

String interpolation inserts values with braces.

println("hello, {name}")

For complex expressions, bind a value first and interpolate the name.

let id = ticket["id"]
println("{id}: ready")

Declarations

Function Declarations

Functions are declared with fn.

fn add(a, b) {
    return a + b
}

Typed signatures may be used when the program benefits from explicit contracts.

fn label(id: string, title: string) -> string {
    return "{id}: {title}"
}

The conventional executable entrypoint is:

fn main() {
    println("hello")
}

Decorator Declarations

Decorators attach supported metadata to the following function declaration.

@deprecated("use new_priority instead")
fn old_priority(plan, blocked) {
    if plan == "enterprise" and blocked {
        return "P0"
    }
    return "P2"
}

Documented decorators are:

Decorators are declaration metadata. Alef does not specify arbitrary aspect weaving or hidden function-body rewriting as part of the public contract.

Struct Declarations

A struct declares a named record shape.

struct Ticket {
    id: string,
    title: string,
    blocked: bool
}

Construct a struct with named fields.

let ticket = Ticket {
    id: "TD-101",
    title: "Checkout timeout",
    blocked: true
}

Read a field with dot access.

println(ticket.title)

Enum Declarations

An enum declares a finite set of cases.

enum Status {
    Triage,
    Progress,
    Done,
}

Enum variants may carry values.

enum Shape {
    Circle(f64),
    Rect(f64, f64),
    Point,
}

Statements

Let Statements

let binds a local value.

let status = "triage"

Bindings may be reassigned when a program is modeling a state transition.

status = "progress"

Return Statements

return exits the current function.

fn owner(priority) {
    if priority == "P0" {
        return "incident-lead"
    }
    return "support"
}

If Statements

if selects a branch based on a boolean condition.

if blocked {
    return "P0"
}
return "P2"

else may be used when both branches are useful.

if blocked {
    println("needs attention")
} else {
    println("moving")
}

For Statements

for iterates over iterable values such as arrays.

for ticket in tickets {
    println(ticket["id"])
}

While Statements

while repeats while its condition is true.

while retries < 3 {
    retries = retries + 1
}

Match Statements

match selects a branch by value shape.

match result {
    Ok(value) => println(value),
    Err(error) => println("failed: {error}"),
}

match is the preferred way to handle Result, Option, and enums in public examples.

Expressions

Expressions produce values.

Calls

println("hello")
priority("enterprise", true)

Operators

Arithmetic:

let total = subtotal + tax
let next = count + 1

Comparison:

let ok = priority == "P0"
let retry = attempts < 3

Boolean logic:

let urgent = blocked and plan == "enterprise"
let visible = not hidden

Boolean operators use words: and, or, and not.

Arrays

let statuses = ["triage", "progress", "done"]
println(statuses[0])

Arrays preserve order and can be traversed with for.

Maps

Maps use => for key/value pairs.

let ticket = {
    "id" => "TD-101",
    "blocked" => true
}

Map values are read with bracket access.

println(ticket["id"])

Maps are the natural shape for JSON-like data and beginner examples.

Types

The public type names used in this book include:

string int f64 bool

Collection and algebraic shapes include:

[T]
Result<T, E>
Option<T>

Struct and enum declarations introduce named types.

Result

Result<T, E> represents success or failure.

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Use Result when an operation can fail.

fn divide(a: f64, b: f64) -> Result<f64, string> {
    if b == 0.0 {
        return Err("division by zero")
    }
    return Ok(a / b)
}

The ? operator unwraps Ok(value) and returns early on Err(error).

fn half_twice(n: f64) -> Result<f64, string> {
    let x = divide(n, 2.0)?
    let y = divide(x, 2.0)?
    return Ok(y)
}

Option

Option<T> represents a value that may be present or absent.

enum Option<T> {
    Some(T),
    None,
}

Use Option when missing data is expected.

Imports And Modules

Imports bring names into scope.

import std.http { json_response }

Standard-library modules are part of the public language surface. The private compiler and runtime source are not required to use them.

Composition And Inversion Of Control

Alef programs can use inversion of control through runtime boundaries such as the HTTP app, route handlers, middleware, state, tests, and benchmark runners.

The public language contract favors explicit composition over hidden auto-wiring:

fn make_service(clock) {
    return { "clock" => clock }
}

fn main() {
    let service = make_service("2026-06-28T10:00:00Z")
    println(service["clock"])
}

There is no documented built-in dependency injection container. Pass dependencies through parameters, app state, and small composition functions.

Program Execution

Run a file with:

alef run main.alef

The shorter form also runs a file:

alef main.alef

This documentation prefers the explicit run form.

Complete Example

fn priority(plan, blocked) {
    if plan == "enterprise" and blocked {
        return "P0"
    }
    return "P2"
}

fn main() {
    let ticket = {
        "id" => "TD-101",
        "plan" => "enterprise",
        "blocked" => true
    }

    let p = priority(ticket["plan"], ticket["blocked"])
    let id = ticket["id"]
    println("{id}: {p}")
}

Expected output:

TD-101: P0

Stability

This specification defines the documented public contract for the current release candidate. If implementation behavior differs from this page, treat the mismatch as a documentation or runtime bug to be fixed.