C+
Language · v0.0.13

Operators and arithmetic

Default arithmetic: checked in debug, wraps in release

let a: i32 = 10 + 20;
let c: i32 = 10 / 3;        // 3
let d: i32 = 10 % 3;        // 1
let e: i32 = 10 - 20;       // -10

Default arithmetic is overflow-checked in debug builds and wraps in release. Division by zero always traps, in both modes.

Wrapping operators: always wrap

When you genuinely want wrap-on-overflow, use the %-suffixed family. They make the intent explicit, because silent overflow is a footgun you should opt into:

let a: u8 = 250u8 +% 10u8;  // 4
let b: i8 = 100i8 *% 3i8;   // overflows, wraps silently
let c: i32 = 0 -% 1;        // -1, the canonical "this can underflow" idiom

Bitwise and shifts

let h: i32 = 0xff & 0x0f;   // 15
let i: i32 = 0xf0 | 0x0f;   // 255
let j: i32 = 0xff ^ 0xaa;   // 85
let k: i32 = 1 << 8;        // 256
let l: i32 = 256 >> 2;      // 64
let m: u32 = ~(0 as u32);   // 0xffffffff

Right shift on a signed type is arithmetic (sign-preserving); on an unsigned type it is logical (zero-fill).

Byte-swap intrinsics

let port_be: u16 = htons(8080 as u16);
let n: u32      = bswap32(0x12345678 as u32);

htons / htonl convert host order to network order. bswap16 / bswap32 / bswap64 are unconditional swaps.

Comparisons

let lt: bool = a < b;
let eq: bool = a == b;      // no coercion
let ne: bool = a != b;

Casts: every width change is explicit

let x: i64 = 5;
let y: i32 = x as i32;
let f: f64 = (x as f64);
let z: usize = 10 as usize;

There is no int to bool, and no silent narrowing. A pointer and an integer convert only through usize, never through i32.