Variables & Types

Turbo is statically typed with type inference. You get safety without verbosity.

Variable Declarations

Use let to declare immutable variables and let mut for mutable ones:

fn main() {
    let name = "Turbo"          // immutable, type inferred as str
    let age: i64 = 1            // explicit type annotation
    let mut counter = 0         // mutable
    counter += 1                // OK -- counter is mutable

    // name = "other"           // ERROR: cannot assign to immutable variable
}

Primitive Types

TypeDescriptionExample
i3232-bit signed integerlet x: i32 = 42
i6464-bit signed integerlet x = 42
u3232-bit unsigned integerlet x: u32 = 42
u6464-bit unsigned integerlet x: u64 = 42
f3232-bit floatlet x: f32 = 3.14
f6464-bit floatlet x = 3.14
boolBooleanlet x = true
strStringlet x = "hello"
()Unit (void)fn noop() { }

Type Inference

Turbo infers types from context. You rarely need to write type annotations:

fn main() {
    let x = 42              // inferred as i64
    let y = 3.14            // inferred as f64
    let name = "hello"      // inferred as str
    let flag = true         // inferred as bool
    let nums = [1, 2, 3]   // inferred as [i64]
}

String Interpolation

Embed expressions inside strings using curly braces:

fn main() {
    let name = "Turbo"
    let version = 1
    print("Welcome to {name} v{version}!")
    // Output: Welcome to Turbo v1!
}

Constants

Top-level constants are declared with const:

const MAX_SIZE: i64 = 1024
const PI: f64 = 3.14159

fn main() {
    print(MAX_SIZE)
    print(PI)
}

Arrays

Arrays are ordered, homogeneous collections:

fn main() {
    let nums = [1, 2, 3, 4, 5]
    print(nums[0])              // 1
    print(len(nums))            // 5

    let mut items = [10, 20, 30]
    items[0] = 99               // mutation requires let mut
    push(items, 40)             // append to array
    print(items.len())          // 4
}

Array Operations

fn main() {
    let nums = [3, 1, 4, 1, 5, 9, 2, 6]

    // map, filter, reduce
    let doubled = nums.map(|x: i64| -> i64 { x * 2 })
    let big = nums.filter(|x: i64| -> bool { x > 4 })
    let sum = reduce(nums, 0, |acc: i64, x: i64| -> i64 { acc + x })
    print(sum)
}

Hashmaps

fn main() {
    let m = hashmap()
    hashmap_set(m, "name", "Turbo")
    hashmap_set(m, "version", "1")
    print(hashmap_get(m, "name"))       // Turbo
    print(hashmap_has(m, "version"))    // true
    print(hashmap_len(m))               // 2

    let keys = hashmap_keys(m)
    print(keys.len())                   // 2
}

Optionals and Results

Turbo has built-in optional and result types for safe error handling:

// Optional: T? represents a value that may be absent
fn find(items: [str], target: str) -> str? {
    // ...
}

// Unwrap with ?? (default value)
let result = find(items, "key") ?? "not found"

// Result: T ! E represents success or error
fn parse(input: str) -> i64 ! str {
    // ...
}

// Propagate errors with ?
fn process() -> i64 ! str {
    let value = parse("42")?    // returns error if parse fails
    value * 2
}

Copy-on-Write Semantics

Turbo uses copy-on-write for safe value semantics without a garbage collector:

fn main() {
    let a = [1, 2, 3]
    let b = a           // shared (cheap)
    b[0] = 99           // copy-on-write (safe)
    print(a[0])          // 1 -- original unchanged
    print(b[0])          // 99 -- independent copy
}