Operators

Operators

Operators are not built into the numeric types alone. An operator applied to an object routes to a trait method, so any class can support it by implementing the matching trait. An operator applied to a raw FFI scalar lowers directly to a machine instruction.

Operator to trait

Operator Trait Method
+ Plus<T> plus
- Minus<T> minus
* Multiply<T> multiply
/ Divide<T> divide
** Exp<T> exp
% Mod<T> modulo
== Equals<T> equals
!= NotEquals<T> not_equals
> GreaterThan<T> greater_than
< LessThan<T> less_than
>= GreaterThanEquals<T> greater_than_equals
<= LessThanEquals<T> less_than_equals
&& And<T> and
`\ \ `
! Not not

Two more traits back the indexing and iteration syntax:

Syntax Trait Method
a[i] Index<I, R> index
a[i] = v IndexRef<I, R> index_ref
for x in a Iter<T> the iterator protocol

Hash backs use as a Map key, paired with Equals.

Dispatch is by method name

The compiler looks for a method with the right name and signature, not for a declared impl. A class that defines equals(other: X) => bool supports == whether or not it declares impl Equals<X>.

The declaration still matters for bounds. A type that only has the method does not satisfy impl Equals, so it cannot be used where that bound is required, such as a Map key. Declare the trait when the type should work generically.

&& and || between two booleans short-circuit on the raw value and never call And or Or.

Implementing an operator

A class opts in by implementing the trait:

[public] class Vector impl Plus<Vector> {
    x: number
    y: number

    [public] fn plus(other: Vector) => Vector {
        return new Vector(this.x + other.x, this.y + other.y)
    }
}

With that in place, a + b on two Vector values calls plus.