Custom Operators

Types provide custom operator implementations to override the behavior of many of the standard Unary and Binary Operartor Expressions for specific type combinations.

Foer 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 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
Plus + Unary, +5
Minus - Unary, -5
BitwiseNot not Bitwise not
not Logical not (not supported)
   
Increment ++ (not callable from Oxygene)
Decrement -- (not callable from Oxygene)
Implicit Implicit
Explicit Explicit Manual type casts with as or ()
True True  
False False  
Add + "5+3"
Subtract - "5-3"
Multiply * "5*3"
Divide /, div "5/3"
Modulus mod "5 mod 3"
BitwiseAnd and Bitwise "and"
BitwiseOr or Bitwise "or"
BitwiseXor xor Bitwise "xor"
ShiftLft shl  
ShiftRight shr  
Equal =  
NotEqual , <>  
Less <  
LessOrEqual , <=  
Greater >,  
GreaterOrEqual , >=  
In in Sets
and Logical (not supported)
or Logical (not supported)
xor Logical (not supported)

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 Constants

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