Implementing Binary Operations
Go Up to Creating a Class to Enable the Custom Variant Type
To allow the custom variant type to work with standard binary operators (+, -, *, /, div, mod, shl, shr, and, or, xor listed in the System unit), you must override the BinaryOp method. BinaryOp
has three parameters: the value of the left-hand operand, the value of the right-hand operand, and the operator. Implement this method to perform the operation, and return the result using the same variable that contained the left-hand operand.
For example, the following BinaryOp
method comes from the TComplexVariantType
defined in the System.VarCmplx unit:
Delphi:
procedure TComplexVariantType.BinaryOp(var Left: TVarData; const Right: TVarData;
const Operator: TVarOp);
begin
if Right.VType = VarType then
case Left.VType of
varString:
case Operator of
opAdd: Variant(Left) := Variant(Left) + TComplexVarData(Right).VComplex.AsString;
else
RaiseInvalidOp;
end;
else
if Left.VType = VarType then
case Operator of
opAdd:
TComplexVarData(Left).VComplex.DoAdd(TComplexVarData(Right).VComplex);
opSubtract:
TComplexVarData(Left).VComplex.DoSubtract(TComplexVarData(Right).VComplex);
opMultiply:
TComplexVarData(Left).VComplex.DoMultiply(TComplexVarData(Right).VComplex);
opDivide:
TComplexVarData(Left).VComplex.DoDivide(TComplexVarData(Right).VComplex);
else
RaiseInvalidOp;
end
else
RaiseInvalidOp;
end
else
RaiseInvalidOp;
end;
There are several things to note in this implementation:
This method only handles the case where the variant on the right side of the operator is a custom variant that represents a complex number. If the left-hand operand is a complex variant and the right-hand operand is not, the complex variant forces the right-hand operand first to be cast to a complex variant. It does this by overriding the RightPromotion method so that it always requires the type in the VarType
property:
Delphi:
function TComplexVariantType.RightPromotion(const V: TVarData;
const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
begin
{ Complex Op TypeX }
RequiredVarType := VarType;
Result := True;
end;
The addition operator is implemented for a string and a complex number (by casting the complex value to a string and concatenating), and the addition, subtraction, multiplication, and division operators are implemented for two complex numbers using the methods of the TComplexData
object that is stored in the data of the complex variant. This is accessed by casting the TVarData
record to a TComplexVarData
record and using its VComplex
member.
Attempting any other operator or combination of types causes the method to call the RaiseInvalidOp
method, which causes a runtime error. The TCustomVariantType
class includes a number of utility methods such as RaiseInvalidOp
that can be used in the implementation of custom variant types.
BinaryOp
only deals with a limited number of types: strings and other complex variants. It is possible, however, to perform operations between complex numbers and other numeric types. For the BinaryOp
method to work, the operands must be cast to complex variants before the values are passed to this method. We have already seen (above) how to use the RightPromotion
method to force the right-hand operand to be a complex variant if the left-hand operand is complex. A similar method, LeftPromotion, forces a cast of the left-hand operand when the right-hand operand is complex:
Delphi:
function TComplexVariantType.LeftPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
begin
{ TypeX Op Complex }
if (Operator = opAdd) and VarDataIsStr(V) then
RequiredVarType := varString
else
RequiredVarType := VarType;
Result := True;
end;
This LeftPromotion
method forces the left-hand operand to be cast to another complex variant, unless it is a string and the operation is addition, in which case LeftPromotion
allows the operand to remain a string.