Get Started

Your first steps with Ferrite.

1

Installation

Install Ferrite using the appropriate method for your OS from the Downloads page.

Verify installation:

ferrite --version
2

Write Code

Create a new file named hello.fe and add the following:

keep message: string = "Hello, Ferrite!";
println(message);
3

Run

Execute your program using the interpreter:

ferrite run hello.fe

Expected output: Hello, Ferrite!

Ferrite Tutorial

Learn the language from scratch.

Chapter 1.1: Hello World

Welcome to Ferrite! Let's start with the classic first program.

In Ferrite, you can use the built-in println function to output text to the console.

println("Hello, World!");
Try in Playground →

Chapter 1.2: Variables & Types

Ferrite is strictly typed. You must declare the type of a variable. By default, variables are declared with the keep keyword.

keep age: int = 25;
keep name: string = "Ferris";
keep is_active: bool = true;
keep pi: float = 3.14159;

Variables are immutable constants by default. You can reassign them if you want, but their type can never change.

keep count: int = 1;
count = count + 1; // Allowed
// count = "two"; // Error: Type mismatch

Chapter 2.1: If & Else

Conditional logic in Ferrite uses standard if, else if, and else blocks. Note that there are no parentheses around the condition!

keep score = 85;

if score >= 90 {
    println("Grade: A");
} else if score >= 80 {
    println("Grade: B");
} else {
    println("Grade: C");
}

Chapter 2.2: Loops

Ferrite primarily uses while loops for iteration. You can use skip to continue to the next iteration, and stop to break out of the loop.

keep i = 0;
while i < 5 {
    i = i + 1;
    if i == 3 {
        skip; // Skips printing 3
    }
    println("Count: " + str(i));
}

Chapter 3.1: Enums & Match

Ferrite supports powerful algebraic datatypes using enum, and deep pattern matching with the match keyword.

You can also use if clauses inside match arms as "guards" for extra conditions!

enum Result<T> {
    Ok(T);
    Err(string);
}

keep response = Ok(200);

match response {
    case Ok(status) if status == 200 => {
        println("Success!");
    }
    case Ok(status) => {
        println("Other status: " + str(status));
    }
    case Err(msg) => {
        println("Error: " + msg);
    }
}

Chapter 4.1: Groups

Instead of classes or structs, Ferrite uses group to define collections of data.

group Vector2 {
    x: float;
    y: float;
}

keep position = Vector2 { x: 10.5, y: 20.0 };
println("X Coordinate: " + str(position.x));

Chapter 4.2: Traits (Interfaces)

A trait defines shared behavior (like an interface). You can then use the impl block to implement that behavior for a specific group.

trait Display {
    fun format(self) -> string;
}

impl Display for Vector2 {
    fun format(self) -> string {
        return "Vec2(" + str(self.x) + ", " + str(self.y) + ")";
    }
}

println(position.format());

Chapter 5.1: Tensors

Tensors are native primitives in Ferrite. When you declare a Tensor, you specify its shape in the type signature. The compiler checks these shapes during compile time!

import "math";

// Define a 1x4 input tensor and a 4x2 weights tensor
param inputs: Tensor<float, (1, 4)> = rand(1, 4);
param weights: Tensor<float, (4, 2)> = ones(4, 2);

// Matrix multiplication using the @ operator
// Resulting shape will automatically be (1, 2)
keep outputs = inputs @ weights;

Chapter 5.2: Execution Blocks

Ferrite uses specialized contexts for ML operations. For example, infer {} blocks optimize execution for pure feed-forward passes by disabling gradient tracking overhead.

infer {
    keep outputs = inputs @ weights;
    println("Outputs: " + str(outputs));
}

train {
    // Operations here will track gradients
    keep loss = compute_gradients(inputs);
}