C+
Language · View as Markdown
v0.0.27 is a macOS / AppKit release. That is the supported path. Other platforms are not recommended; wait for a later version.

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.

Checked narrowing: as?

n as? u8 evaluates to Option[u8]: Some(converted) when the value is representable in the target, None otherwise. Integer source and target only (E0315 names the offending side). The infallible as keeps its truncating semantics for the cases where truncation is intended.

import "stdlib/option" as option;

fn as_byte(n: i32) -> option::Option[u8] {
    return n as? u8;
}

Codegen is a 64-bit bounds check selecting the Option tag and payload. Needs stdlib/option in the build.