Djinn Lang

Operator Overloading

Djinn allows user-defined types to define custom behavior for built-in operators like +, ==, -, and others. Operators can be declared inside a struct body or in a separate impl block.

Syntax

An operator overload is declared with the operator keyword followed by the operator symbol, a parameter list, a return type, and a body:

operator +(Vec2 left, Vec2 right) -> Vec2 {
    return { .x = left.x + right.x, .y = left.y + right.y };
}

Operators Inside Struct Bodies

Operators can be defined directly inside the struct definition:

struct Vec2 {
    i32 x;
    i32 y;

    operator +(Vec2 left, Vec2 right) -> Vec2 {
        return { .x = left.x + right.x, .y = left.y + right.y };
    }
}

i32 main() {
    Vec2 a = { .x = 10, .y = 20 };
    Vec2 b = { .x = 5, .y = 7 };
    Vec2 c = a + b;
    return c.x + c.y; // 42
}

Operators in impl Blocks

Operators can also be defined in a separate impl block:

struct Vec2 {
    i32 x;
    i32 y;
}

impl Vec2 {
    operator +(Vec2 left, Vec2 right) -> Vec2 {
        return { .x = left.x + right.x, .y = left.y + right.y };
    }
}

Equality Operators

Define == to enable equality comparisons. The compiler automatically derives != from ==, so you only need to implement one:

struct Point {
    i32 x;
    i32 y;
}

impl Point {
    operator ==(Point left, Point right) -> bool {
        return left.x == right.x && left.y == right.y;
    }
}

i32 main() {
    Point a = { .x = 5, .y = 10 };
    Point b = { .x = 5, .y = 10 };
    Point c = { .x = 1, .y = 2 };

    if (a == b) { /* true  */ }
    if (a != c) { /* true — derived automatically */ }
}

Multiple Operators

A struct can define as many operators as needed:

struct Vec2 {
    i32 x;
    i32 y;

    operator +(Vec2 left, Vec2 right) -> Vec2 {
        return { .x = left.x + right.x, .y = left.y + right.y };
    }

    operator ==(Vec2 left, Vec2 right) -> bool {
        return left.x == right.x && left.y == right.y;
    }
}

i32 main() {
    Vec2 a = { .x = 3, .y = 4 };
    Vec2 b = { .x = 3, .y = 4 };
    Vec2 c = { .x = 6, .y = 8 };

    Vec2 sum = a + b;
    if (sum == c) {
        return 99;
    }
    return 0;
}

Operators in Interfaces

Interfaces can declare operator signatures that implementing structs must provide:

interface IEquatable<T> {
    operator ==(T left, T right) -> bool;
}

Overloadable Operators

CategoryOperators
Arithmetic+, -, *, /, %
Comparison==, !=, <, <=, >, >=
Bitwise&, |, ^, ~, <<, >>

Bitwise Operators on Primitives

Bitwise operators work on integer primitives without needing overloads:

i32 main() {
    i32 a = 12;  // 1100
    i32 b = 10;  // 1010

    i32 and_result = a & b;   // 1000 = 8
    i32 or_result  = a | b;   // 1110 = 14
    i32 xor_result = a ^ b;   // 0110 = 6
    i32 not_result = ~a;
    i32 shl_result = 1 << 3;  // 8
    i32 shr_result = 16 >> 2; // 4
}

Derived Operators

When you define ==, the compiler automatically provides != as its logical negation. You do not need to implement != separately.

On this page