Operator traits

Operator traits

Operators are not built in to the numeric types. An operator applied to an object calls a method; an operator applied to a raw machine scalar lowers directly to an instruction.

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

Dispatch is by method name

This is the part that surprises people. 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 says impl Equals<X>.

xml::Element is exactly that case: it defines equals but does not declare the trait.

The declaration still matters for bounds. A type that only has the method satisfies the operator but 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 is meant to be usable generically.

Short-circuiting

&& and || between two booleans short-circuit on the raw value and never call And or Or. Enum comparison with == compares the variant directly.

Implementing one

[public] class Money impl Plus<Money>, Equals<Money> {
    cents: i64

    [public] fn plus(other: Money) => Money {
        return new Money(this.cents + other.cents)
    }

    [public] fn equals(other: Money) => bool {
        return this.cents == other.cents
    }
}