Custom Operators
Types provide custom operator implementations to override the behavior of many of the standard Unary and Binary Operator Expressions for specific type combinations.
For example, if a class or record contains data that, logically, a +
operation would make sense for, a custom Add
operator can be provided to allow the expression a + b
to be evaluated using the correct rules.
Note: Custom Operators (like Constructors and Finalizers ) are very similar in structure to regular methods, and many topics covered in the Methods topic will apply to them as well.
This includes the sections on Parameters, Result, Method Body and Pre- and Post-Conditions.
Operators can be defined for Classes and Records, as well as for other types (including external ones) via Extensions or as Globals).
The following standard operators can be overridden: +
, -
, *
, /
, div
, mod
, and
, or
, xor
, <
, ≤
, =
, >
, ≥
and ≠
. In addition, two cast operators, Implicit
and Explicit
, can be provided to allow implicit and explicit casting from and to other types.
A custom operator declaration consists of the operator
keyword and the operator name, always followed by a list of parameters in parenthesis, and a result type. The names and list of parameters are well-defined and must match the table below.
Operators are always considered static; the static
Member Modifier or a class
keyword prefix are optional for consistency, and have no effect.
type
ComplexNumber = public record
public
Real: Double;
Imagnary: Double;
operator Add(lhs: ComplexNumber, rhs: ComplexNumber): ComplexNumber;
operator Implict(aOther: Double): ComplexNumber;
operator Explicit(aOther: Double): ComplexNumber;
operator Explicit(aOther: ComplexNumber): Double;
end;
At least one parameter (or, for casts, the result) must be of the type that the operator is defined on. The other parameter can be of a different type:
operator Add(lhs: ComplexNumber, rhs: Double): ComplexNumber;
operator Add(lhs: Double, rhs: ComplexNumber): ComplexNumber;
Using Operators
Expressions using the above operators will automatically use custom operators, the right and left hand side of the expression (or just the single operand, for Unary Operators such as not
) are strongly typed to match the parameters of an operator (or one of the base classes).
For example, an Add
operator defined such as
type
Foo = class
operator Add(aFoo: Foo; aOther: Object);
would be called for any expression such as a + b
where a
is of type Foo
, and b
is any type (that descends from Object
).
Note that the operands need to be strongly typed, as operator overloading is resolved at compile time. For example, in the following scenario, the custom operator would not be called, even though a
holds a Foo
class at runtime, because to the compiler, a
is just an object, and operarors are not Polymorphic:
var a: Object := new Foo();
var b: Object := "Hello"
var x := a+b;
Operators can be kept "flexible" by keeping one parameter weakly-typed (such as in the example above), and checking for the best operation at runtime, in the operator's implementation. For example, the above operator allows to add a Foo
instance to just about anything else – be it a String
, an Integer
, or even anotherFoo
. It is then up to the implementation to take the appropriate action depending on the type of aOther
.
Operator Names
The following special names need to be used when implementing operators:
Name | Oxygene Operator | Comments/Example |
---|---|---|
Plus |
+ |
Unary, +5 |
Minus |
- |
Unary, -5 |
BitwiseNot |
not |
Bitwise not : not $00ff |
LogicalNot |
not |
Logical not : if not true |
Increment |
inc() |
maps to the single parameter inc() system function, and ++ in C# & Co) |
Decrement |
dec() |
maps to the single parameter dec() system function, and -- in C# & Co) |
Implicit |
— | Automatic (implicit) type casts |
Explicit |
Explicit |
Manual (explicit) type casts with as or () |
True |
— | Returns whether a value represent "true " |
False |
— | Returns whether a value represent "false " |
Add |
+ |
"5+3 " |
Subtract |
- |
"5-3 " |
Multiply |
* |
"5*3 " |
Divide |
/ , div |
"5/3 ", "5 div 3 " |
IntDivide |
div |
"5 div 3 " (only with Delphi-style Divisions enabled) |
Modulus |
mod |
"5 mod 3 " |
Pow |
** |
x to the power of y, e.g.: "10**5 " |
BitwiseAnd |
and |
Bitwise "and", $08ad and $00ff = $00ad |
BitwiseOr |
or |
Bitwise "or", $08ad or $00ff = $08ad |
BitwiseXor |
xor |
Bitwise "xor", $08ad or $00ff = $0852 |
ShiftLeft |
shl |
|
ShiftRight |
shr |
|
Equal |
= |
|
NotEqual |
≠ , <> |
|
Less |
< |
|
LessOrEqual |
≤ , <= |
|
Greater |
> , |
|
GreaterOrEqual |
≥ , >= |
|
In |
in |
Checks if the left value is contained in the right |
— | and |
Logical "and" (cannot be overloaded) |
— | or |
Logical "or" (cannot be overloaded) |
— | xor |
Logical "xor" (cannot be overloaded) |
Box |
— | Used when boxing value types |
Unbox |
— | Used when un-boxing value types |
Assign |
:= |
Used when assigning records (Island only) |
IsNil |
— | Returns whether a value represents "unassigned"/nil |
The following alias names are supported for Delphi Compatibility:
Name | Equivalent to | Comment |
---|---|---|
Inc |
Increment |
|
Dec |
Decrement |
|
Positive |
Plus |
|
Negative |
Minus |
|
LessThan |
Less |
|
LessThanOrEqual |
LessOrEqual |
|
GreaterThan |
Greater |
|
GreaterThanOrEqual |
GreaterOrEqual |
|
LeftShift |
ShiftLeft |
|
RightShift |
ShiftRight |
Visibility
The visibility of operators is governed by the Visibility Section of the containing type the operator is declared in, or the Visibility Modifiers applied to the operator.
Static/Class Annotations
Operators are always static and do not have access to instance data (except of course the instances passed in as parameters). They do not need to (but are allowed to) be prefixed with the class
keyword or have a static
Member Modifier.
Virtuality
Since operators are always static, they do not participate in Polymorphism, and cannot have Virtuality Modifiers.
Other Modifiers
A number of other Member Modifiers can be applied to operators.
deprecated
Triggers a deprecation warning when used.empty
Empty body; when calling this does nothing.inline
Makes the body of this method inlined when calling this.locked
Like locked on, with Self as an expression.locked on
Does a lock on Expression around the body of this method.mapped to
(See Mapped Members).raises
Defines the Java raises condition for this operator; this is the list of exceptions it might throw.unsafe
(See Unsafe Code on .NET).
See Also
- Operators
- Unary Operators
- Binary Operators
inc()
anddec()
System Functions