# Integer Rules

> Arbitrary widths, explicit narrowing, chosen overflow behaviour.

```zig
const std = @import("std");
const expect = std.testing.expect;

test "arbitrary bit widths" {
    // Any width from u0/i0 up to u65535 is a real type.
    const small: u3 = 7;
    try expect(@as(u8, small) == 7);
    try expect(std.math.maxInt(u3) == 7);
}

test "widening is implicit, narrowing is not" {
    const a: u8 = 200;
    const b: u16 = a; // always safe, so allowed
    try expect(b == 200);

    // `const c: u8 = b;` would not compile. Say what you mean:
    const c: u8 = @intCast(b); // checked in safety builds
    try expect(c == 200);
}

test "wrapping and saturating operators" {
    const max: u8 = 255;
    // Plain `max + 1` is illegal behaviour (a panic in safety builds).
    try expect(max +% 1 == 0); // wrapping
    try expect(max +| 1 == 255); // saturating
}

test "overflow can be detected instead" {
    const max: u8 = 255;
    const result = @addWithOverflow(max, 1);
    try expect(result[0] == 0); // wrapped value
    try expect(result[1] == 1); // overflow bit set
}

test "comptime_int has no width" {
    // Literals are arbitrary precision until they are given a type.
    const big = 1 << 100;
    try expect(big > 0);
    try expect(@TypeOf(1 + 1) == comptime_int);
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`02-language.integer-rules`)*

## Any width you like

`u3`, `i7`, `u64`, `u1000` are all real types. `u8` is not special, it is just
the one that happens to be a byte. Packed structs use this to describe bitfields
exactly.

## Widening is free, narrowing is not

`u8` → `u16` is always safe, so Zig does it implicitly. The reverse can lose
data, so it must be written:

```zig
const c: u8 = @intCast(b);
```

In a safety-enabled build `@intCast` panics if the value does not fit. In
`ReleaseFast` it is illegal behaviour. Either way, the cast is visible in the
source, so you cannot lose the top bits by accident.

## Overflow is a decision

Plain `+` on integers **traps** on overflow rather than wrapping. If you want
different behaviour, ask for it:

| Operator | On overflow |
| --- | --- |
| `+` `-` `*` | illegal behaviour (panics in safety builds) |
| `+%` `-%` `*%` | wrap around |
| `+\|` `-\|` `*\|` | saturate at the type's limit |

Or detect it: `@addWithOverflow(a, b)` returns a tuple of the wrapped result
and an overflow bit.

This is C's biggest silent-corruption source turned into an explicit choice.

## `comptime_int`

Literals have no width until they are assigned one. `1 << 100` is fine at
compile time; it only needs to fit once it becomes a runtime value.
