# Primitives and literals

## Integer and float types

| Category | Types |
|---|---|
| Signed | `i8 i16 i32 i64 isize` |
| Unsigned | `u8 u16 u32 u64 usize` |
| Float | `f16 f32 f64` |

There is no `int`, no `long`, no `byte`. The size is part of the name.

`f16` is the IEEE half-precision float (2 bytes), primarily a **storage** type for ML and graphics data. It converts to and from the wider floats with `as` (hardware `fpext` / `fptrunc`), and exposes a bit-preserving reinterpret to and from its raw `u16`:

```cplus
let h: f16 = 1.5f32 as f16;          // fptrunc
let x: f32 = h as f32;               // fpext

let h2: f16 = f16::from_bits(0x3C00 as u16);   // IEEE half 1.0
let raw: u16 = h2.to_bits();
```

Arithmetic on `f16` works, but the idiomatic hot-path pattern is to convert to `f32`, compute, then convert back.

## Other primitives

- `bool`: `true` / `false`. It **cannot** be produced by an integer cast.
- `()`: the unit type, the implicit return of a function with no arrow.
- `str`: a string view (pointer plus length), borrowed.
- `string`: an owned, heap-allocated string, provided by the standard library.
- `*T`: a raw pointer. Operations require `unsafe`.
- `fn(...) -> R`: a function pointer.

## Literals

```cplus
let a: i32 = 42;
let b: u64 = 42u64;            // typed literal
let c: f64 = 3.14;
let d: bool = true;
let e: str = "hello";
let f: i32 = 0x1F;             // hex
let g: i32 = 0b1010;           // binary
let h: i32 = 1_000_000;        // underscore separators
```

Character literals: `'a'` is a `u8` byte literal, a shorter way to write `97u8`. The backslash escapes `'\n'`, `'\t'`, `'\r'`, `'\\'`, `'\''`, `'\"'`, `'\0'`, and the hex form `'\xFF'` all work. A multi-byte UTF-8 codepoint such as `'á'` is rejected at parse time, since the type is `u8`, not a full Unicode codepoint. For UTF-8 use a `str`.
