Operators, Overflow and Casting
6.1 Operators
+ - * / % (integer / requires known-positive operands or @divTrunc/@divFloor/@divExact for signed values) +% -% *% (two's complement wrap) +| -| *| <<| (clamp to min/max) and or ! (short-circuit) orelse, .? catch, try, || (merge error sets)
++ (concatenation, comptime), ` (repetition, comptime) No operator overloading.** a + b` always means numeric addition.
No ++/-- increment operators. Use x += 1.
6.2 Integer Overflow
var a: u8 = 255;
// a += 1; // Debug/ReleaseSafe: panic "integer overflow"
a +%= 1; // wraps to 0
var b: u8 = 250;
b +|= 10; // saturates at 255
const res = @addWithOverflow(@as(u8, 200), 100); // tuple { result, overflow_bit }
std.debug.print("{d} {d}\n", .{ res[0], res[1] }); // 44 1
// also @subWithOverflow, @mulWithOverflow, @shlWithOverflow
// std.math.add(u8, a, b) returns error.Overflow6.3 Division
const x: i32 = -7;
_ = @divTrunc(x, 2); // -3
_ = @divFloor(x, 2); // -4
_ = @divExact(8, 2); // 4 (UB if not exact; checked in safe modes)
_ = @rem(x, 2); // -1
_ = @mod(x, 2); // 16.4 Type Coercion and Casting
Implicit coercion is only allowed when it's lossless and safe: u8 → u16, i8 → i16, comptime_int → any integer that fits, *T → ?*T, [N]T pointer → slice, T → ?T, T → E!T, etc.
Since 0.11, cast builtins infer their result type from context. Use @as(T, @intCast(x)) when there's no context.
const small: u8 = 200;
const big: u32 = small; // OK: widening
const explicit = @as(u16, small); // @as: explicit, safe coercion
const narrowed: u8 = @intCast(big); // checked narrowing (panics in safe modes if it doesn't fit)
const truncated: u8 = @truncate(@as(u32, 0x1234)); // 0x34 (discard high bits)
const f: f32 = @floatFromInt(big);
const i: i32 = @intFromFloat(3.99); // 3 (UB if out of range)
const fl: f32 = @floatCast(@as(f64, 1.5));
const bits: u32 = @bitCast(@as(f32, 1.0)); // reinterpret bits
const e: u8 = @intFromEnum(Color.red);
const c: Color = @enumFromInt(1);
const b: u1 = @intFromBool(true);