TODO: clarify whether these are instance or associated members and specify when they must be one or the other. Also, can operators be declared as stand alone functions?
An operator overload is a method that defines the meaning of an operator expression when applied
to instances of the class. Operators are declared similarly to functions using operator
declarations. These declarations use _ as a placeholder to indicate the positions of the operands.
This distinguishes nullary, unary prefix, unary postfix, and binary operators.
Operator overloads can be generic functions. To make one generic place the generic parameters after
the operator keyword. However, since it isn't possible to pass generic parameters when using
operators, they are limited to cases where the generic parameters can be inferred.
operator_declaration
: access_modifier attributes operator_name parameters function_body
;
operator_name
: "operator" generic_parameters overloadable_operator
| "implicit" "operator" literal_operator
;
overloadable_operator
: overloadable_nullary_operator
| overloadable_unary_operator
| "_" overloadable_bindary_operator "_"
;
overloadable_nullary_operator
: ".."
| "<.."
| "..<"
| "<..<"
;
overloadable_unary_operator
: "+" "_"
| "-" "_"
| "^" "_"
| ".." "_"
| "<.." "_"
| "..<" "_"
| "<..<" "_"
| "_" ".."
| "_" "<.."
| "_" "..<"
| "_" "<..<"
;
overloadable_binary_operator
: "+"
| "-"
| "*"
| "/"
| ".."
| "<.."
| "..<"
| "<..<"
| "+="
| "-="
| "*="
| "/="
;
literal_operator
: "'_'"
| ?String literal for single underscore (i.e. "_" including the double quotes)?
;
Most overloadable operators act as simple methods. However, some operators require special handling or have special effects. This table summarizes which operators are overloadable and if they require special handling.
| Operators | Overloadability |
|---|---|
+ , - , ^ |
These unary operators can be overloaded |
@ , =>, not |
These unary operators can't be overloaded |
+ , - , * , / |
The arithmetic operators can be overloaded |
+= , -= , *= , /= |
The arithmetic assignment operators can be overloaded for greater efficiency |
.. , <.. , ..< , <..< |
The range operators can each be overloaded independently |
:: , ^. , | , & |
These binary operators can't be overloaded |
as , as! , as? |
The conversion operators are not overloadable |
== , =/= , < , > , <= , >= |
The comparison operators can be overloaded in pairs |
and , or, ?., ?? , . |
Support for overloading these operators is planned for future releases |
= , -> , f(x) |
These operators can't be overloaded |
These types are used for the examples in the following sections.
public copy value complex
{
public let real: float;
public let imaginary: float;
public init(.real, .imaginary) { }
}
public copy value fuzzy_bool
{
public let value: float;
public init(.value)
requires value >= 0 and value <=1
{
}
}
Four unary operators are overloadable. The + and - operators are straightforward overloads. Note
that both are prefix operators and their declarations have a single operand placeholder after the
operator.
// In `complex`
public operator +_(self) -> complex
{
// return a copy, unchanged
return self;
}
public operator -_(self) -> complex
{
return complex(-real, -imaginary);
}
It is not possible to overload the dereference and access operator ^. directly. However, when the
dereference operator ^ is overloaded it will be used to evaluate the ^. operator by first
calling the overloaded dereference operator and then applying standard member access to the
resulting value. The dereference operator is overloadable to allow for value types that act like
pointers. The dereference operator is a prefix operator, so its declaration has a single operand
placeholder after the operator.
public drop value unique_pointer[T]
where T: value
{
private let ptr: @T;
public safe operator ^_(self) -> Ref[T]
{
return unsafe(Ref(*ptr));
}
}
The binary arithmetic operators + , - , * , and / can be overloaded.
// In `complex`
public operator _+_(self, other: complex) -> complex
{
return complex(real + other.real, imaginary + other.imaginary);
}
In order to support operators whose left hand side is a primitive type. In binary operators, the self parameter may be the second parameter.
// In `complex`
public operator _+_(self, other: float) -> complex
{
return complex(real + other, imaginary);
}
// In `complex`
public operator _+_(other: float, self) -> complex
{
return complex(other + real, imaginary);
}
These operators will be automatically generated if the corresponding binary operator is overloaded. However, they can be directly overloaded for greater efficiency, different behavior or to mark them as uncallable.
The range operators can each be overloaded independently. However, it is recommend that the exclusive range operators be overloaded as a set. The inclusive range operators can be used as unary operators for open ended ranges. Furthermore they can be used as nullary operators for open ranges. The nullary, unary prefix, unary suffix and binary forms of these operators are distinguished by their operand placeholders.
The comparison operators can be overloaded like other binary operators. However, they must overloaded in pairs. When one of the operators in the pair is overloaded, the other one in the pair must be overloaded to.
| Operator | Pairs |
|---|---|
== |
=/= |
> |
< |
>= |
<= |
For operators that have multiple syntax forms, these are all treated as equivalent.
Note: The obsolete attribute can be used to mark a member of the pair as uncallable if it is
explicitly desired not to implement the other member of the pair.