Skip to content
Xen / docs

Search documentation

English · v0.1.0-demo.2

Type to search the documentation.

    한국어
    Xen / learn v0.1.0-demo.2

    Data types and conversions

    A type determines which values a variable can hold and which operations apply. This chapter explains numeric widths, explicit conversions, and places where inference needs help. Read Variables and values first.

    TypeUse and constraints
    Int (I64)Default integer type for whole-number calculations.
    I8, I16, I32, I64Signed 8-, 16-, 32-, and 64-bit integers.
    U8, U16, U32, U64Unsigned integers. For example, U8 ranges from 0 to 255.
    Float (F64), F32Calculations with a fractional part.
    Booltrue or false; required for conditions.
    StringAn immutable sequence of bytes.
    UnitNo result; its value is ().

    Without a determining context, integer literals default to Int and floating literals to Float. An annotation such as let count: I32 = 42; supplies that context. A variable that already has a numeric type is not implicitly converted to another one.

    Save this as data_types.xen. i64, u8, and float create values of the requested type; they do not change the type of the original variable.

    data_types.xen
    fn main() {
    let narrow: I32 = 42;
    let wide: Int = i64(narrow);
    let small: U8 = u8(255);
    let half: Float = float(wide) / 2.0;
    println(wide);
    println(small);
    println(half);
    println(5 / 2);
    println(float(5) / 2.0);
    println("한".len());
    }
    Terminal window
    xen check data_types.xen
    xen run data_types.xen
    data_types.stdout
    42
    255
    21.0
    2
    2.5
    3

    5 / 2 produces 2 because both operands are integers. Convert before division when you need a fraction: float(5) / 2.0. Writing float(5 / 2) converts the already computed integer 2; it cannot recover the discarded fraction.

    The final 3 is the number of UTF-8 bytes in "한". String length is not a character count, and character indexing is unavailable.

    This complete program deliberately fails. Save it as numeric_mismatch.xen and run xen check numeric_mismatch.xen.

    numeric_mismatch.xen
    fn main() {
    let wide: Int = 42;
    let narrow: I32 = wide;
    println(narrow);
    }

    The diagnostic includes this text; paths and line numbers are omitted:

    numeric_mismatch.stderr
    expected I32, found Int (I64)

    Change the declaration to let narrow: I32 = i32(wide);. When converting to a smaller type, also consider whether the value fits its range.

    Distinguish conversion failure from arithmetic wrapping

    Section titled “Distinguish conversion failure from arithmetic wrapping”

    An out-of-range conversion behaves differently from overflowing integer addition.

    • u8(255) succeeds, while an out-of-range literal such as u8(256) is rejected during checking.
    • A conversion of an out-of-range value at runtime terminates with a runtime error.
    • Integer +, -, and * wrap at the type’s limits. Conversion checks do not imply that arithmetic operations have the same checks.
    • Division by zero, and division of a signed minimum by -1, are runtime errors.

    The following program passes xen check conversion_error.xen but fails under xen run conversion_error.xen:

    conversion_error.xen
    fn main() {
    let value = 256;
    println(u8(value));
    }
    conversion_error.stderr
    numeric conversion to U8 failed

    An empty collection or a variant with no payload cannot identify its item type:

    let values: Vec<Int> = [];
    let missing: Option<String> = Option.None;

    Function parameters and return types are explicit too. Generic functions infer type arguments from arguments, rather than just the receiving variable’s type. Generics and type inference explains that distinction.

    Representation neededChoice
    Many values of one typeVec<T>
    Different values grouped by positionA tuple such as (Int, String)
    Named fieldsstruct
    One of several formsenum, Option<T>, Result<T, E>
    A temporary read-only view without copyingSlice<T>
    An owned recursive connectionBox<T>

    These choices also affect copying and how long values remain usable. Continue with structs and enums, copies, moves, and references, and slices and iterators. Use the type reference for the rules.

    Replace float(5) / 2.0 with float(5 / 2) and explain the changed output. Choose a value for U8, then consider whether its real input could exceed 255.