Documentation channel: current development main at compiler checkpoint 1d7e15e. The latest tagged release is v0.0.3; pages identify APIs that are not yet released.

Operators

Strut has a fixed, language-defined operator table. Packages may overload the enabled operators, but they cannot invent punctuation or change precedence. Overloads are free declarations, not methods, so operand order and symmetry are explicit.

Overload table

FormOperatorsOverloadableDeclaration contract
Infix arithmetic+ - * / %YesTwo parameters; any declared return type.
Infix comparison== != < <= > >=YesTwo parameters; return bool.
Infix logical/bitwise|| && | ^ &YesTwo parameters. Logical overloads return bool; bitwise overloads may return a domain type.
Infix shifts<< >>YesTwo parameters; return the shifted or stream type.
Prefix+ - ! ~ * ++ --YesOne parameter; return type is explicit.
Postfix++ --YesOne parameter followed by the compiler marker postfix.
Assignment= :=YesTwo parameters. The destination is first; use a reference destination for =.
Null coalescing??NoLanguage-defined nullable semantics.
Index and call[] ()NoReserved syntax; source overload declarations are not enabled yet.

Certified examples for every enabled family

This single example declares and executes arithmetic, comparison, bitwise/logical-family, shift, prefix, initialization, and assignment overloads. It is compiled and run by the documentation suite, so every “Yes” row above has executable proof.

struct Number { int value; }
struct Config { int value; }

operator +(Number a, Number b) -> Number {
    return Number { value: a.value + b.value };
}

operator ==(Number a, Number b) -> bool {
    return a.value == b.value;
}

operator &(Number a, Number b) -> Number {
    return Number { value: a.value & b.value };
}

operator <<(Number value, int amount) -> Number {
    return Number { value: value.value << amount };
}

operator -(Number value) -> Number {
    return Number { value: -value.value };
}

operator ++(Number& value) -> Number& {
    value.value = value.value + 1;
    return value;
}

operator ++(Number& value, postfix) -> Number {
    previous := Number { value: value.value };
    value.value = value.value + 1;
    return previous;
}

operator :=(Number destination, Config source) -> void {
    destination.value = source.value;
}

operator =(Number& destination, Config source) -> void {
    destination.value = source.value;
}

function main() -> int {
    one := Number { value: 1 };
    two := Number { value: 2 };
    sum := one + two;
    same := sum == Number { value: 3 };
    masked := sum & Number { value: 1 };
    shifted := masked << 2;
    negative := -shifted;
    before := sum++;
    updated := ++sum;
    Number configured := Config { value: 7 };
    configured = Config { value: 9 };
    println(same);
    println(negative.value);
    println(before.value);
    println(updated.value);
    println(configured.value);
    return 0;
}

Resolution rules

Binary overloads are ordered: operator +(Left, Right) does not imply operator +(Right, Left). Declare both when an operation is intentionally symmetric across different types. The declared return type controls the expression type and may differ from either operand.

Prefix and postfix increment/decrement are separate overload identities. ++value selects only operator ++(T& value), while value++ selects only operator ++(T& value, postfix). The postfix word is compile-time signature syntax: it is not a type, runtime argument, or body-visible parameter. Conventionally prefix returns the updated T& and postfix returns the previous T; return types do not determine which overload is selected.

= mutates existing storage and therefore normally takes T& as its first parameter. := constructs new storage and receives a destination value plus its source. These are dedicated language lowering points rather than native C++ assignment declarations.

Generic overloads

operator[T] +(Vector<T> a, Vector<T> b) -> Vector<T> {
    return Vector<T> { x: a.x + b.x, y: a.y + b.y };
}

Callable-form declarations

operator<(Vector, Vector) -> Vector> + :=
    (a, b) => Vector { x: a.x + b.x, y: a.y + b.y };