Implementing Binary Operations

From RAD Studio
Jump to: navigation, search

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.

See Also