Types

Dogma is statically typed. All types are checked at compile time using Hindley-Milner inference — you rarely need to annotate explicitly.

Primitives🔗

TypeDescriptionLiteral example
i3232-bit signed integer42
i6464-bit signed integer9999999999
f3232-bit float3.14
f6464-bit float3.14159265
boolBooleantrue, false
StringUTF-8 string"hello"
()Unit — no valueReturn type of fn main()

Arrays🔗

let numbers: [i32] = [1, 2, 3, 4, 5]
let first = numbers[0]        // i32
let length: i32 = numbers.len()

Arrays are immutable by default. Use push/pop from dogma:core to create new arrays. arr.len() returns i32 — use i32 for loop counters over arrays.

Structs🔗

struct Player {
    name: String,
    health: i32,
}

impl Player {
    fn is_alive(self) -> bool {
        self.health > 0
    }
}

fn main() {
    let p = Player { name: "Aria", health: 100 }
    if p.is_alive() { println("Alive!") }
}

Enums🔗

enum Direction {
    North,
    South,
    East,
    West,
}

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
}

fn area(s: Shape) -> f64 {
    match s {
        Shape::Circle(r) => 3.14159 * r * r,
        Shape::Rectangle(w, h) => w * h,
    }
}

Option<T>🔗

Represents a value that may or may not be present.

fn find(items: [String], target: String) -> Option<i32> {
    let mut i: i32 = 0
    while i < items.len() {
        if items[i] == target { return Some(i) }
        i = i + 1
    }
    None
}

match find(["a", "b", "c"], "b") {
    Some(idx) => println(f"Found at {idx}"),
    None => println("Not found"),
}

Result<T, E>🔗

Represents success (Ok) or failure (Err).

fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 { Err("division by zero") }
    else { Ok(a / b) }
}

Use the ? operator to propagate errors — see Error Handling.

Generics🔗

fn first<T>(items: [T]) -> Option<T> {
    if items.len() == 0 { None }
    else { Some(items[0]) }
}

What is not implemented🔗

pub/visibility modifiers, trait bounds (T: Display), dyn Trait, operator overloading, macros, async/await, JIT/AOT.