The assignment operator defines the action of a assignment of one type of variable to another. The result type must match the type of the variable at the left of the assignment statement, the single parameter to the assignment operator must have the same type as the expression at the right of the assignment operator.
This system can be used to declare a new type, and define an assignment for that type. For instance, to be able to assign a newly defined type “Complex”
Var C,Z : Complex; // New type complex begin Z:=C; // assignments between complex types. end;
The following assignment operator would have to be defined:
Operator := (C : Complex) z : complex;
To be able to assign a real type to a complex type as follows:
var R : real; C : complex; begin C:=R; end;
the following assignment operator must be defined:
Operator := (r : real) z : complex;
As can be seen from this statement, it defines the action of the operator := with at the right a real expression, and at the left a complex expression.
An example implementation of this could be as follows:
operator := (r : real) z : complex; begin z.re:=r; z.im:=0.0; end;
As can be seen in the example, the result identifier (z in this case) is used to store the result of the assignment. When compiling in Delphi mode or ObjFPC mode, the use of the special identifier Result is also allowed, and can be substituted for the z, so the above would be equivalent to
operator := (r : real) z : complex; begin Result.re:=r; Result.im:=0.0; end;
The assignment operator is also used to convert types from one type to another. The compiler will consider all overloaded assignment operators till it finds one that matches the types of the left hand and right hand expressions. If no such operator is found, a “type mismatch” error is given.
Remark The assignment operator is not commutative; the compiler will never reverse the role of the two arguments. In other words, given the above definition of the assignment operator, the following is not possible:
var R : real; C : complex; begin R:=C; end;
If the reverse assignment should be possible then the assignment operator must be defined for that as well. (This is not so for reals and complex numbers.)
Remark The assignment operator is also used in implicit type conversions. This can have unwanted effects. Consider the following definitions:
operator := (r : real) z : complex; function exp(c : complex) : complex;
Then the following assignment will give a type mismatch:
Var r1,r2 : real; begin r1:=exp(r2); end;
The mismatch occurs because the compiler will encounter the definition of the exp function with the complex argument. It implicitly converts r2 to a complex, so it can use the above exp function. The result of this function is a complex, which cannot be assigned to r1, so the compiler will give a “type mismatch” error. The compiler will not look further for another exp which has the correct arguments.
It is possible to avoid this particular problem by specifying
r1:=system.exp(r2);
When doing an explicit typecast, the compiler will attempt an implicit conversion if an assignment operator is present. That means that
Var R1 : T1; R2 : T2; begin R2:=T2(R1);
Will be handled by an operator
Operator := (aRight: T1) Res: T2;
However, an Explicit operator can be defined, and then it will be used instead when the compiler encounters a typecast.
The reverse is not true: In a regular assignment, the compiler will not consider explicit assignment operators.
Given the following definitions:
uses sysutils; type TTest1 = record f: LongInt; end; TTest2 = record f: String; end; TTest3 = record f: Boolean; end;
It is possible to create assignment operators:
operator := (aRight: TTest1) Res: TTest2; begin Writeln('Implicit TTest1 => TTest2'); Res.f := IntToStr(aRight.f); end; operator := (aRight: TTest1) Res: TTest3; begin Writeln('Implicit TTest1 => TTest3'); Res.f := aRight.f <> 0; end;
But one can also define typecasting operators:
operator Explicit(aRight: TTest2) Res: TTest1; begin Writeln('Explicit TTest2 => TTest1'); Res.f := StrToIntDef(aRight.f, 0); end; operator Explicit(aRight: TTest1) Res: TTest3; begin Writeln('Explicit TTest1 => TTest3'); Res.f := aRight.f <> 0; end;
Thus, the following code
var t1: TTest1; t2: TTest2; t3: TTest3; begin t1.f := 42; // Implicit t2 := t1; // theoretically explicit, but implicit op will be used, // because no explicit operator is defined t2 := TTest2(t1); // the following would not compile, // no assignment operator defined (explicit one won't be used here) //t1 := t2; // Explicit t1 := TTest1(t2); // first explicit (TTest2 => TTest1) then implicit (TTest1 => TTest3) t3 := TTest1(t2); // Implicit t3 := t1; // explicit t3 := TTest3(t1); end.
will produce the following output:
Implicit TTest1 => TTest2 Implicit TTest1 => TTest2 Explicit TTest2 => TTest1 Explicit TTest2 => TTest1 Implicit TTest1 => TTest3 Implicit TTest1 => TTest3 Explicit TTest1 => TTest3