Types and OOP Operators

Operator Overloading

Define operators as statically typed class methods. Prefix and postfix operations have distinct declarations; their return values and mutations are explicit in your code.

Supported Operators

Instance unary operators have no explicit operand parameter; instance binary operators receive the other operand. Static unary and binary overloads receive one and two operands, respectively. Resolution follows static parameter types, visibility, and the normal method dispatch rules. Redefinition does not change precedence.

FamilyOperatorsDeclaration / Contract
Arithmetic+ - * / // % ** @For example, operator+(other as Point) as Point.
Equality and ordering== != < <= > >=Comparison overloads return Boolean.
Bitwise& | ^ << >>Binary methods receive the other operand.
Compound assignment+= -= *= /= //= %= **= @= &= |= ^= <<= >>=For example, operator+=(other as Point) as Void explicitly mutates the receiver.
Unary+ - ~ notFor example, operator~() as Mask; not returns Boolean.
Prefix++value --valueoperator++() / operator--().
Postfixvalue++ value--operator()++ / operator()--; parameterless instance methods.
Indexingvalue[index]operator[] with get and/or set accessors.
Membershipitem in containeroperator in(item as T) as Boolean belongs to the container, on the right.
Pattern matchingvalue =~ patternoperator=~(pattern as String) as Boolean.
Invocationvalue(arguments)operator ()(...) with ordinary typed parameters.

Declare each supported form explicitly: an equality overload does not automatically supply every comparison, and a prefix overload does not supply a postfix overload. Compound assignments such as value += other may have their own overload, whose return value is discarded. Without a compound overload, the corresponding binary operation and assignment require an assignable, type-compatible result. Mutating the receiver and replacing the variable with another instance are different contracts; choose explicitly. Membership negation, item not in container, negates operator in.

Language syntax is not an overload

Assignment =, type tests is, casts as, and sizeof are language operations, not custom operator methods. Native Boolean and and or short-circuit; a custom lazy overload contract is not currently supported and must not be inferred from an ordinary binary method declaration.

Declarations and Examples

class Point:
    public x as Int
    public y as Int

    public Point(x as Int, y as Int):
        this.x = x
        this.y = y

    public operator+(other as Point) as Point:
        return Point(this.x + other.x, this.y + other.y)

    public operator+=(other as Point) as Void:
        this.x += other.x
        this.y += other.y

    public operator==(other as Point) as Boolean:
        return this.x == other.x and this.y == other.y

first = Point(1, 2)
second = Point(3, 4)
assert first + second == Point(4, 6)
assert first.x == 1
alias = first
first += second
assert alias == Point(4, 6)

Operators use ordinary syntax at the call site. A type may define only the operators that make sense for its domain.

Unary +, -, ~, and not also use ordinary method resolution. An instance overload has no explicit operand parameter; a static overload has one. The operand is evaluated exactly once, and the usual visibility and virtual dispatch rules apply. An overload of not must return Boolean.

class Mask:
    public bits as Int

    public Mask(bits as Int):
        this.bits = bits

    public operator~() as Mask:
        return Mask(~this.bits)

inverted = ~Mask(0)
assert inverted.bits == -1

Prefix and Postfix Increment / Decrement

Increment and decrement have distinct prefix and postfix overloads: operator++() and operator--() implement ++value and --value; operator()++ and operator()-- implement value++ and value--. Postfix declarations are parameterless instance methods: the empty parentheses precede the symbol, with no second parameter list. Each form uses ordinary visibility and virtual dispatch and evaluates its receiver exactly once. No overload is substituted for a missing form, and no copy is implicit. The overload's declared return type determines the expression's type.

class Counter:
    public value as Int = 0

    public operator++() as Counter:
        this.value++
        return this

    public operator()++ as Counter:
        previous = Counter()
        previous.value = this.value
        this.value++
        return previous

    public operator--() as Counter:
        this.value--
        return this

    public operator()-- as Counter:
        previous = Counter()
        previous.value = this.value
        this.value--
        return previous

counter = Counter()
previous = counter++
assert previous.value == 0
assert counter.value == 1
current = ++counter
assert current.value == 2
previous = counter--
assert previous.value == 2
assert counter.value == 1
current = --counter
assert current.value == 0

Returning this preserves identity; constructing another object preserves a snapshot. Writing previous = this only creates an alias and does not preserve the previous state. Boolean and and or short-circuit: their right operand is evaluated only when the left operand does not determine the result.

Callable Instances

Define operator () to make a class instance callable. Its parameters, return type, default arguments, and access checks follow the same rules as an ordinary method. Calling the instance does not implicitly call a method named invoke. The first empty pair () names the operator; the second pair contains its parameters. For a parameterless call operator, write operator ()(). This is distinct from the postfix declarations operator()++ and operator()--.

class Multiplier:
    public operator ()(value as Int = 2) as Int:
        return value * 3

multiply = Multiplier()
assert multiply(5) == 15
assert multiply() == 6
assert (multiply)(5) == 15

Indexed Access

Declare indexed reads and writes with one operator[] member. The setter receives the assigned value through value. Declare only get for a read-only indexer, or only set for a write-only indexer. Do not declare operator[]=. Multiple typed index parameters are allowed, for example operator[](row as Long, column as Long).

Accessors must be indented one level below the indexer declaration, with their bodies one level further. Each accessor may be declared at most once, and a concrete indexer must declare at least one accessor. Reading a write-only indexer or assigning through a read-only indexer is rejected at compilation with TypeError.

class Slot:
    private _stored as Int = 0

    public operator[](index as Long) as Int:
        get:
            if index != 0:
                throw IndexException("Only index 0 exists")
            return this._stored
        set:
            if index != 0:
                throw IndexException("Only index 0 exists")
            this._stored = value

slot = Slot()
slot[0] = 42
assert slot[0] == 42

Membership

class Interval:
    public operator in(value as Int) as Boolean:
        return 1 <= value <= 3

interval = Interval()
assert 2 in interval
assert 4 not in interval

The receiver is the right operand. This instance method takes exactly one item parameter and returns Boolean; it is not a parameter-passing qualifier.