TYCHO Search

Search documentation

    ↑ ↓ to move · Enter to open · Esc to close

    8. Conversions and casts

    Tycho performs no implicit conversion of values between types. Distinct scalar types never mix in an operation, and no value silently widens or narrows. The only implicit adaptation is of literals (§8.1); every value-level conversion is an explicit builtin call (§8.2).

    8.1 Literal adaptation

    An integer or floating-point literal — an int/float literal token, not a typed value or variable — adapts to the type expected by its context. Adaptation changes the type the literal is compiled to; it never changes a variable's type and never converts a value at run time. The permitted adaptations are:

    A char literal does not adapt. Division or modulo by a literal zero is a compile-time error (a zero *value* at run time aborts, §30). There is no source-level numeric suffix (§3.9.1); the destination type drives adaptation. Adaptation distributes over the elements of an array literal when the destination is an array type: in a: [u32] = [1, 2] each element is checked against u32 and each literal adapts, exactly as in the fixed a: [3]u32 = [1, 2, 3] and bounded a: bounded[4]u32 = [1, 2] forms. A bracket literal with no destination still synthesizes its type from its first element.

    8.2 Explicit conversion builtins

    Each conversion is a builtin call with a fixed accepted-type set and result type. base_of in the "accepts" column means the operand's underlying type is consulted (so a newtype over the listed base is accepted).

    BuiltinAcceptsYieldsNotes
    str(x)int, any sized int, f32, bool, float, string, char (through base_of)stringpolymorphic; identity on string; a char → its one-byte glyph
    to_int(x)float, any sized int, f32, char, or an int-newtypeinttruncates toward zero for float; a NaN/out-of-range float aborts (§8.5)
    to_float(n)int, any sized int, f32, or a float-newtypefloat
    to_u8 … to_i64, to_f32any numeric scalar: int, char, float, or any sized int/float (through base_of)the named fixed-width typenarrowing / reinterpretation; total (defined for every input). to_i32 recovers a 32-bit C int return over FFI
    to_str(x)bytes, or a string-newtypestringzero-cost reinterpret (same buffer)
    to_bytes(x)string, bytes (through base_of), [int], or a packed structbytesstring/bytes: same buffer, distinct type (zero-cost reinterpret). [int]: each element truncated & 0xFF into a fresh buffer — builds a binary bytes (interior 0x00 allowed). Packed struct: exactly size_of$(T) bytes, little-endian
    to_bool(x)a bool-newtypeboolnewtype unwrap
    to_under(x)any newtypeits underlying typegeneric newtype unwrap, zero-cost
    to_ptr(n)intptrFFI sentinel pointer; never dereferenced
    to_char(n)intcharthe byte value as a char; a value outside 0..255 aborts (§29.4) — the same conversion as chr(n), differing only in whether the byte comes back as a char or a one-byte string. The yielded type has no keyword (§5.2.4), so it is only ever inferred

    Each takes exactly one argument. str is the conversion used by f-string interpolation (§3.9.5): because a hole desugars to str(hole), a hole MUST have a type str accepts.

    8.3 Newtype unwrapping

    A value of a newtype X = U is unwrapped to its U value by the base-specific conversion — to_int (U = int), to_float (U = float), to_str (U = string), to_bool (U = bool) — or by the generic to_under, which yields the underlying type of any newtype. Unwrapping is zero-cost (a newtype is erased in lowering, §5.4).

    8.4 Hard errors

    The following are compile-time type errors, not conversions:

    8.5 Out-of-range conversions

    For an in-range operand, to_int(f) truncates f toward zero, and each sized conversion narrows by the modular/reinterpreting rule of §8.2. A to_int of a float/f32 that is NaN or outside the signed 64-bit range aborts (tycho: float-to-int conversion out of range) rather than inheriting C's undefined float-to-integer behavior — the fail-closed discipline. The sized integer/float conversions (to_u8 … to_i64, to_f32) are total: they narrow by taking the low bits or reinterpreting (§8.2), so every input has a defined result.