Operator Overloading

-a, ++a, ~a, *a opBinary!"op", opBinaryRight!"op" a < b, <=,...

a[i], a[i] = v, a[i] += v opIndex, opIndexAssign, opIndexOpAssign a[i.. j], $ opSlice, opDollar foreach (x; a) opApply (or range primitives)

struct Vec2
{
    double x, y;

    Vec2 opBinary(string op)(Vec2 rhs) const if (op == "+" || op == "-")
    {
        return mixin("Vec2(x " ~ op ~ " rhs.x, y " ~ op ~ " rhs.y)");
    }
    Vec2 opBinary(string op : "*")(double k) const { return Vec2(x * k, y * k); }
    Vec2 opBinaryRight(string op : "*")(double k) const { return this * k; }   // k * v
    Vec2 opUnary(string op : "-")() const { return Vec2(-x, -y); }
    ref Vec2 opOpAssign(string op)(Vec2 rhs) { mixin("x " ~ op ~ "= rhs.x; y " ~ op ~ "= rhs.y;"); return this; }
    bool opEquals(const Vec2 o) const { return x == o.x && y == o.y; }
    int opCmp(const Vec2 o) const { import std.math : cmp; return cmp(x * x + y * y, o.x * o.x + o.y * o.y); }
    double opIndex(size_t i) const { return i == 0 ? x : y; }
    void opIndexAssign(double v, size_t i) { if (i == 0) x = v; else y = v; }
    T opCast(T : bool)() const { return x != 0 || y != 0; }
    double opCall() const { import std.math : sqrt; return sqrt(x * x + y * y); }   // v()
    size_t toHash() const nothrow @safe { return hashOf(x) ^ hashOf(y); }
}
struct Tree
{
    int[] data;
    int opApply(scope int delegate(ref int) dg)    // custom foreach iteration
    {
        foreach (ref x; data) if (auto r = dg(x)) return r;
        return 0;
    }
}