LEARN RYFT

Types & errors

Structs, enums, exhaustive matching, generics and JSON codecs.

Ryft checks types before generating native code. There are no implicit conversions between strings, integers and booleans. Values have copy-like semantics: generated code clones owned strings, JSON and model values when necessary.

Structs and value methods

struct Task { title: String; complete: bool; }
impl Task {
    fn finish(self: Task) -> Task {
        let mut changed = self;
        changed.complete = true;
        return changed;
    }
}
fn main() {
    let task = Task { title: "Ship Ryft", complete: false };
    let finished = task.finish();
    assert(finished.complete);
    assert(!task.complete);
}

Fields can be assigned through a mutable local. Methods consume a copy-like owned value; they do not borrow and mutate the caller’s original. References, pointers and mutable receiver borrowing are not exposed.

Enums and exhaustive matching

enum Status { todo, done }
enum Message { Text(String), Count(i64) }
fn describe(message: Message) -> String {
    match message {
        Message.Text(text) => { return text; },
        Message.Count(number) => { return to_string(number); }
    }
}

All variants must be handled once, with the correct payload binding. A variant can carry one value. Use a struct when a payload needs multiple fields. Unit enums support equality; payload enums are inspected with matching.

Result and Option

Result<T,E> has Ok(T) and Err(E). Option<T> has Some(T) and None. Handle them explicitly:

fn parse_count(text: String) -> i64 {
    match parse_i64(text) {
        Ok(value) => { return value; },
        Err(message) => { return 0; }
    }
}
test expected_errors {
    assert(parse_count("42") == 42);
    assert(parse_count("not a number") == 0);
    let missing = Option<String>.None;
    match missing {
        Some(value) => { assert(false); },
        None => { assert(true); }
    }
}

Use Result<i64,String>.Err("reason") when constructing a result whose other type cannot be inferred. There is no ? propagation operator, exception syntax or implicit result unwrapping. Use fallible parsing for untrusted inputs; strict conversion builtins can fail the handler at runtime.

Typed collections

test collections {
    let numbers: List<i64> = list_push(list(10, 20), 30);
    match list_at(numbers, 2) {
        Some(number) => { assert(number == 30); },
        None => { assert(false); }
    }
    let counts = map_put(Map<String, i64>.new(), "tasks", 3);
    match map_get(counts, "tasks") {
        Some(count) => { assert(count == 3); },
        None => { assert(false); }
    }
}

List<T>.new() constructs an empty typed list. list(...) requires at least one homogeneous argument. List indexing is zero-based and returns Option<T>; missing keys do the same. Maps currently require String keys. list_push and map_put return updated values; keep the returned value. JSON arrays remain dynamically typed Json values and are distinct from List<T>.

Inferred generic functions

fn identity<T>(value: T) -> T { return value; }
fn singleton<T>(value: T) -> List<T> { return list(value); }
test inference {
    assert(identity(42) == 42);
    assert(identity("Ryft") == "Ryft");
    assert(len(singleton(true)) == 1);
}

Call types are inferred from arguments. Repeated occurrences of one type parameter must agree. Generated generic values require cloning. User-defined generic structs, trait constraints and specialization are not implemented.

Strict JSON codecs

Task.from_json(value) returns Result<Task,String>. json(task) or task.to_json() encodes a serializable value. Primitive types, serializable structs/enums and supported containers can participate in codecs. Response values cannot be serialized as data.

Struct decoding rejects missing fields, unknown fields, incorrect types and invalid enum tags. An Option<T> field must still be present; use JSON null for None. Integer fields reject floating-point/exponent spellings. Unit enums encode as strings, such as "todo"; payload enums use {"variant":"Text","value":"hello"}. These codecs validate shape and type; domain rules such as nonempty titles belong in your application.

See the executable feature example and language reference for primitives and control flow.

Ryft 0.3.0Source: docs/types-and-errors.md

Search installation, types, routes, storage and more.