Skip to content

Numeric Types

For APIs that need explicit bit widths — network ports, GPU buffers, C interop — Zolo accepts sub-64 aliases (u8, i32, f32, usize…) both as type annotations and as literal suffixes (42u8, 1.5f32). In the current MVP they all map to int/float; overflow-checked types are planned:

Fixed-width aliases: as annotations and as literal suffixes.

16-numeric-types.zolo
Playground
// Feature: numeric types and literal suffixes (MVP)
// When to use: write APIs whose intent is clearer with explicit widths
//   (`u16` for a port number, `u8` for a byte) or whose values must
//   round-trip through FFI / GPU buffers (`f32`, `u32`).
//
// MVP scope (today): sub-64-bit names (`i8..u64`, `f32`, `f64`,
// `isize`, `usize`) are accepted as type annotations and as literal
// suffixes (`42u8`, `1.5f32`, `42i`). Internally they all map to
// `int` (i64) or `float` (f64) for now — distinct types with range
// checks and overflow semantics land with the full numeric overhaul.
//
// See `specs/numeric-primitive-types.md` and
// `specs/numeric-literal-suffixes.md`.

// 1. Type annotations: sub-64-bit aliases ----------------------------
let port: u16 = 8080
let pixel: u8 = 255
let coord: f32 = 1.5
let offset: i32 = -100
let big: u64 = 1_000_000_000

print("port={port}, pixel={pixel}, coord={coord}, offset={offset}, big={big}")

// 2. Literal suffixes -----------------------------------------------
let f32_val = 1.5f32       // explicit f32
let f_short = 1.5f         // short form (= f32)
let i32_val = 42i32        // explicit i32
let i_short = 42i          // short form (= i32)
let u_short = 42u          // short form (= u32)
let port_lit: u16 = 8080u16

print("f32={f32_val}, f={f_short}, i32={i32_val}, i={i_short}, u={u_short}, port={port_lit}")

// 3. Hex / binary / octal with suffixes -----------------------------
let mask: u32 = 0xFF_FF_00_00u32
let bits: u8 = 0b1010_0001u8
let perms: u16 = 0o644u16

print("mask={mask}, bits={bits}, perms={perms}")

// 4. Underscores for readability ------------------------------------
let count: u64 = 1_000_000_000_000u64
let chunked = 0xFF_FF_FF_FFu32

print("count={count}, chunked={chunked}")

// Future work (with the full numeric overhaul):
//   - Distinct overflow checks (300u8 → compile error today, may
//     wrap silently after the next pass — TBD).
//   - Strict no-implicit conversion between concretes (i32 + i64 →
//     error without `as`).
//   - AbstractInt/AbstractFloat formalized so `let x: u8 = 42` keeps
//     working without a suffix.
//   - SIMD-mapped vector types like `vec3<f32>` as a primitive.

Challenge

The example declares let pixel: u8 = 255 using a type annotation. Rewrite it to use a literal suffix instead (255u8). Does the output change? What happens if you try 256u8?

enespt-br