Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Primitive types

The primitive types, the one sharing regime, and integer semantics.

The type table

GroupTypesNotes
unsigned intu8 u16 u32 u64fixed width
signed inti8 i16 i32 i64two’s complement
floatf32 f64IEEE 754
miscbool
textstrimmutable UTF-8, length-prefixed; compared by content; s.slice(a, b) is an O(1) view (see String slicing and views)
binarybytesimmutable, content-compared octet buffer; the engine-level u8 array
seqVec<T>mutable, growable buffer — shared; a library class over [T] (see Builtin generic types)
seq[T]fixed array — shared; runtime length, non-growable
nullable?Tnil-able cell; nil is the null (see By-reference and nullable)
erasureopaquethe erasure box (see opaque — erasure and downcast)
userstruct / class recordsshared cell handles (see Structs, Classes and constructors)

There is no character type: 'x' does not parse, and str iteration yields one-codepoint strs. Codepoints are spelled with integers:

MemberMeaning
s.code() -> u32the FIRST codepoint of s (traps on empty)
s.code_at(i: i32) -> u32the codepoint at codepoint index i (traps out of bounds — the index is a bug, not data)
str.from_code(n: u32) -> strthe 1-codepoint str for n

There is no null and no undefined: absence is nil on a nullable ?T.

Size and members

.len() is the sequence member shared by every sequence: [T], Vec<T>, str (codepoints), bytes (octets). There is no .length property or .count() variant anywhere in the language.

str members: len(), code(), code_at(i), encode() -> bytes, slice(from, to) -> str, starts_with(from, head) -> bool, scan(from, set) -> i64. bytes members: len(), decode() -> str (UTF-8, lossy), clone() -> bytes; type-methods bytes.zeroed(n) -> bytes and bytes.from(a: [u8]) -> bytes. str.encode() and bytes.decode() convert between text and octets.

One regime: primitives by value, everything else shared

Primitives (u8..u64, i8..i64, f32/f64, bool) and fn values copy on assignment, passing, and return — plain slot moves. Every other type is a refcounted heap cell handle: assignment shares, and mutation through any alias is visible through all of them — struct and class instances, str, bytes, Vec, [T], enums, opaque boxes, trait-typed values, ?T boxes alike. Writing is gated by the mut-binding law (see Modules and visibility), never by the sharing.

There is no eager copy and no own(x): bytes.clone() is the one copy escape hatch. There is no &/* syntax anywhere. == on cells is identity (the raw slot compare); str/bytes compare by content — the full table is in Rc, dispose, and identity.

No box<T>, no loans: a loan needs an exclusivity proof, and rut has no borrow checker. The construct is rejected, not deferred. The only borrows anywhere are host-side, call-scoped ones at the embedding boundary.

Tuples and the answer channel

Tuples are first-class values: type (A, B), value (a, b), numeric field access .0, .1, .., destructuring:

let (lo, hi) = bounds;
fn checked_add(self, y: u8) -> (u8, bool);

(?T, err) — concretely (value, ok) / (T, str) — is the answer channel for results and errors. The convention is law:

  • empty err + a value = success
  • empty err + nil = “not found” (a legitimately absent value)
  • non-empty err = failed

checked_add/checked_sub/checked_mul return (value, ok) — false exactly on overflow, value the wrapped bits either way.

Integer semantics

  • Overflow in + - * << traps in debug and release. Wrapping escapes are compiler-lowered methods, ambient on every integer primitive (no use):

    FamilyMembers
    wrapping (two’s complement)wrapping_add wrapping_sub wrapping_mul wrapping_shl
    saturatingsaturating_add saturating_sub saturating_mul
    checked ((T, bool))checked_add checked_sub checked_mul
  • Division by zero traps; int / int is integer division.

  • Mixed-width arithmetic is an error — both operands must have equal width; convert first with as.

  • Conversions are the numeric cast expr as T, truncating like C/Rust — see Literals and inference. There are no implicit numeric conversions at all.