Docs contents

Types and inference

Contents · New to Nagi? Language guide

Annotate variables with count: i32 = 10, parameters with count: i32, and return values with -> i32. Local annotations can be omitted, but reassignment cannot change an established type.

Type Purpose Limits and value handling
i8 / i16 / i32 / i64 Signed integers; the number is the bit width Copyable; operations between numeric types require explicit conversion
u8 / u16 / u32 / u64 Unsigned integers Copyable; cannot store negative values
f32 / f64 Floating-point numbers Copyable
bool True / False Used in branch and loop conditions
str / bytes UTF-8 strings / byte sequences Owned; passing to a user-defined function moves the value
List[T] / [T] Lists of elements of the same type Owned; for iteration supports primitive elements and Copy classes
view[str] / view[bytes] / view[T] Read borrowed strings, byte sequences, or lists Requires an owner for the source data; read-only
T? / Option[T] A value or None None requires type context
Result[T, Error] A success value or an error Propagate with try, or handle Ok / Err with match
shared[T] An owned value shared across multiple places Create with share; duplicate its shared reference with clone_shared
UUID / timestamp UUID / time values Use uuid_parse / uuid_format for UUID text conversion
fn[parameter types..., return type] Pass a function as a value Supported in synchronous function signatures; the last type is the return type
unit No return value The return type when a function omits its return annotation

count = 10 infers i64; rate = 1.5 infers f64. Annotated integer literals are checked against the type's range. Current conversions are lossless i64(value) from i8/i16/i32/u8/u16/u32 and range-checked i32(value) -> Result[i32, Error] from i64. There is no general cast to arbitrary types.

Floating-point literals are also checked against the f32 or f64 type determined by an annotation, parameter, return type, or other context. A value that would become infinity in that type fails type checking.

In the VS Code extension, hovering a variable shows its inferred type, such as count: i64. This also covers arguments and case bindings. Try the editor walkthrough.

Write missing: i64? = None for an absent nullable value and present: i64? = some(42) for a present value. T? abbreviates Option[T]; matching and a general unwrap API are not yet available. Annotate empty lists, for example values: List[i64] = [].

See syntax for parameter, return, and borrow annotations; ownership for copy and move rules; and built-in functions for accepted argument types.

On this page

Pass a function as a value

A function name can be assigned to a variable or passed to another function. fn[i64, i64] means a function taking one i64 and returning i64. For a function with no parameters, write only its return type, such as fn[i64].

Save this as app.nagi:

def add_one(value: i64) -> i64:
    return value + 1

def apply(callback: fn[i64, i64], value: i64) -> i64:
    return callback(value)

def main():
    chosen: fn[i64, i64] = add_one
    print(apply(chosen, 41))
nagic run app.nagi

The result is 42. Local types can also be inferred: chosen = add_one. A function that returns another function can declare a return type such as def choose() -> fn[i64]:.

You can also assign an async function with selected = answer, then call await selected(...) inside an async function. Type annotations for parameters receiving async functions, or functions returning them, are not yet supported. Lambdas and closures that capture surrounding local variables are also unsupported.

Storing async functions in lists or classes is also unsupported. You cannot store the unawaited result of async work in a variable. Write await sleep(10) rather than pending = sleep(10).

Unsupported type operations

Map[K, V] and owned[T] have type notation but incomplete operation APIs. User-defined generic functions and traits are unsupported.

Rust representation

Numbers and bool map to the same Rust types. str maps to String, bytes and List to Vec, and shared to Arc. Views map to references, nullable values to Option, and success/failure to Result. See memory handling.

Minimum signed integers

The minimum values can be written directly as literals: -128 for i8, -32768 for i16, -2147483648 for i32, and -9223372036854775808 for i64. For example, minimum: i8 = -128. A literal outside the specified type's range fails type checking.

Nagi 0.1 documentationPage source