Operator overloading

Operators can be overloaded for user-defined types by declaring a function named operator followed by the operator. Binary operators are overloaded with free functions taking two parameters. Operator operands can be borrowed implicitly: T& parameters accept values as usual, and lvalues can also fill T* parameters without an explicit &. Ordinary function calls still require & for a T* parameter.

struct Money {
    int cents;
}

Money operator+(Money a, Money b) {
    return Money(a.cents + b.cents);
}

bool operator==(Money a, Money b) {
    return a.cents == b.cents;
}

void main() {
    var a = Money(100);
    var b = Money(250);
    var c = a + b;
    println(c.cents); // prints 350
    println(a + b == c); // prints true
}

The overloadable operators are ==, !=, <, <=, >, >=, +, -, *, /, %, and the subscript operator [] below. Operator functions can be generic, like any other function.

Comparison operators are synthesized, so only == and < need overloads: != is the negation of ==, etc.

Structs also get a default == that compares every member with == and &&s the results together. The default covers != too (members compared with !=, ||ed). Comparing structs of different types is still an error.

The subscript operator is overloaded with a method, so it can access the instance through this:

struct Date {
    int year;
    int month;
    int day;

    int operator[](int index) {
        if index == 0 {
            return year;
        } else if index == 1 {
            return month;
        }
        return day;
    }

    void operator[]=(int index, int value) {
        if index == 0 {
            year = value;
        } else if index == 1 {
            month = value;
        } else {
            day = value;
        }
    }
}

void main() {
    var v = Date(2024, 1, 31);
    println(v[0] + v[1] + v[2]); // prints 2056
    v[1] = 2; // calls operator[]=
    println(v.month); // prints 2
}