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