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
// 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?
See also