Difference between revisions of "Operator overloading"

From Lazarus wiki
Jump to navigationJump to search
(wikify)
 
(12 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Translate}}
+
{{LanguageBar}}
[[Operator]] overloading refers to re-defining already defined operators with new definitions.
 
The term is – although imprecisely – used for operator definitions, that have not yet been defined, too.
 
  
== overloadable operators ==
+
[[Operator]] overloading refers to re-defining already defined [[Operators|operators]] with new definitions.
Operator overloading is not allowed in {$[[Mode TP|mode '''TP''']]} or {$[[Mode MacPas|mode '''MacPAS''']]}.<br>
+
The term is – although imprecisely – used for operator definitions, that have not yet been defined, too.
In {$[[Mode Delphi|mode '''DELPHI''']]}, operator overloading can only be declared as class operator of a class or advanced record [http://docwiki.embarcadero.com/RADStudio/Rio/en/Operator_Overloading_(Delphi)], so mode Delphi does not support global operator overloads like {$[[Mode ObjFPC|mode '''OBJFPC''']]}(or {$[[Mode FPC|mode '''FPC''']]}) does.
+
 
<br>
+
== Availability ==
 +
The [[FPC]] supports [[PXSC]]-style operator overloading, however it is not allowed in [[Mode TP|<syntaxhighlight lang="pascal" inline>{$mode TP}</syntaxhighlight>]] or [[Mode MacPas|<syntaxhighlight lang="pascal" inline>{$mode MacPas}</syntaxhighlight>]].
 +
In [[Mode Delphi|<syntaxhighlight lang="pascal" inline>{$mode Delphi}</syntaxhighlight>]], operator overloading can only be done in the context of classes or advanced records (confer [http://docwiki.embarcadero.com/RADStudio/Rio/en/Operator_Overloading_(Delphi) Delphi documentation]), so the Delphi mode does not support global operator overloads as [[Mode FPC|<syntaxhighlight lang="pascal" inline>{$mode FPC}</syntaxhighlight>]] and [[Mode ObjFPC|<syntaxhighlight lang="pascal" inline>{$mode objFPC}</syntaxhighlight>]] do.
 +
 
 +
== Overloadable operators ==
 
Almost all operators can be (re-)defined:
 
Almost all operators can be (re-)defined:
 
* assignment operators
 
* assignment operators
** [[Becomes|<syntaxhighlight lang="pascal" enclose="none">:=</syntaxhighlight>]]
+
** [[Becomes|<syntaxhighlight lang="pascal" inline>:=</syntaxhighlight>]]
** the special operator <syntaxhighlight lang="delphi" enclose="none">explicit</syntaxhighlight> (referring to explicit [[Typecast|typecasts]])
+
** the special operator <syntaxhighlight lang="delphi" inline>explicit</syntaxhighlight> (referring to explicit [[Typecast|typecasts]])
 
* arithmetic operators
 
* arithmetic operators
** [[Plus|<syntaxhighlight lang="pascal" enclose="none">+</syntaxhighlight>]] (only binary operation)
+
** [[Plus|<syntaxhighlight lang="pascal" inline>+</syntaxhighlight>]] (only binary operation)
** [[Minus|<syntaxhighlight lang="pascal" enclose="none">-</syntaxhighlight>]] (both unary and binary)
+
** [[Minus|<syntaxhighlight lang="pascal" inline>-</syntaxhighlight>]] (both unary and binary)
** [[Asterisk|<syntaxhighlight lang="pascal" enclose="none">*</syntaxhighlight>]]
+
** [[Asterisk|<syntaxhighlight lang="pascal" inline>*</syntaxhighlight>]]
** <syntaxhighlight lang="pascal" enclose="none">**</syntaxhighlight>
+
** <syntaxhighlight lang="pascal" inline>**</syntaxhighlight>
** [[Div|<syntaxhighlight lang="pascal" enclose="none">div</syntaxhighlight>]]
+
** [[Div|<syntaxhighlight lang="pascal" inline>div</syntaxhighlight>]]
** [[Mod|<syntaxhighlight lang="pascal" enclose="none">mod</syntaxhighlight>]]
+
** [[Mod|<syntaxhighlight lang="pascal" inline>mod</syntaxhighlight>]]
** [[Slash|<syntaxhighlight lang="pascal" enclose="none">/</syntaxhighlight>]]
+
** [[Slash|<syntaxhighlight lang="pascal" inline>/</syntaxhighlight>]]
** [[Inc and Dec|<syntaxhighlight lang="pascal" enclose="none">inc</syntaxhighlight>]]
+
** [[Inc and Dec|<syntaxhighlight lang="pascal" inline>inc</syntaxhighlight>]]
** [[Inc and Dec|<syntaxhighlight lang="pascal" enclose="none">dec</syntaxhighlight>]]
+
** [[Inc and Dec|<syntaxhighlight lang="pascal" inline>dec</syntaxhighlight>]]
** (As of 2019 in the future: <syntaxhighlight lang="pascal" enclose="none">pow</syntaxhighlight>)
+
** (As of 2020 in the future: <syntaxhighlight lang="pascal" inline>pow</syntaxhighlight>)
 
* comparison operators
 
* comparison operators
** [[Less than|<syntaxhighlight lang="pascal" enclose="none"><</syntaxhighlight>]]
+
** [[Less than|<syntaxhighlight lang="pascal" inline><</syntaxhighlight>]]
** [[Greater than|<syntaxhighlight lang="pascal" enclose="none">></syntaxhighlight>]]
+
** [[Greater than|<syntaxhighlight lang="pascal" inline>></syntaxhighlight>]]
** <syntaxhighlight lang="pascal" enclose="none">>=</syntaxhighlight>
+
** <syntaxhighlight lang="pascal" inline>>=</syntaxhighlight>
** <syntaxhighlight lang="pascal" enclose="none"><=</syntaxhighlight>
+
** <syntaxhighlight lang="pascal" inline><=</syntaxhighlight>
** [[Equal|<syntaxhighlight lang="pascal" enclose="none">=</syntaxhighlight>]]
+
** [[Equal|<syntaxhighlight lang="pascal" inline>=</syntaxhighlight>]]
** [[Not equal|<syntaxhighlight lang="pascal" enclose="none"><></syntaxhighlight>]]
+
** [[Not equal|<syntaxhighlight lang="pascal" inline><></syntaxhighlight>]]
** [[symmetric difference|<syntaxhighlight lang="pascal" enclose="none">><</syntaxhighlight>]]
+
** [[symmetric difference|<syntaxhighlight lang="pascal" inline>><</syntaxhighlight>]]
** [[In|<syntaxhighlight lang="pascal" enclose="none">in</syntaxhighlight>]]
+
** [[In|<syntaxhighlight lang="pascal" inline>in</syntaxhighlight>]]
** (As of 2019 in the future: <syntaxhighlight lang="pascal" enclose="none">EQ</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">LT</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">GT</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">NE</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">LE</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">GE</syntaxhighlight>)
 
 
* logical operators
 
* logical operators
** [[And|<syntaxhighlight lang="pascal" enclose="none">and</syntaxhighlight>]]
+
** [[And|<syntaxhighlight lang="pascal" inline>and</syntaxhighlight>]]
** [[Or|<syntaxhighlight lang="pascal" enclose="none">or</syntaxhighlight>]]
+
** [[Or|<syntaxhighlight lang="pascal" inline>or</syntaxhighlight>]]
** [[Not|<syntaxhighlight lang="pascal" enclose="none">not</syntaxhighlight>]]
+
** [[Not|<syntaxhighlight lang="pascal" inline>not</syntaxhighlight>]]
** [[Xor|<syntaxhighlight lang="pascal" enclose="none">xor</syntaxhighlight>]]
+
** [[Xor|<syntaxhighlight lang="pascal" inline>xor</syntaxhighlight>]]
** [[Shl|<syntaxhighlight lang="pascal" enclose="none">shl</syntaxhighlight>]]
+
** [[Shl|<syntaxhighlight lang="pascal" inline>shl</syntaxhighlight>]]
** [[Shr|<syntaxhighlight lang="pascal" enclose="none">shr</syntaxhighlight>]]
+
** [[Shr|<syntaxhighlight lang="pascal" inline>shr</syntaxhighlight>]]
** (As of 2019 in the future: <syntaxhighlight lang="pascal" enclose="none">and_then</syntaxhighlight>, <syntaxhighlight lang="pascal" enclose="none">or_else</syntaxhighlight>)
+
** (As of 2020 in the future: <syntaxhighlight lang="pascal" inline>and_then</syntaxhighlight>, <syntaxhighlight lang="pascal" inline>or_else</syntaxhighlight>)
* and the special operator [[for-in loop#Declaring enumerators|<syntaxhighlight lang="delphi" enclose="none">enumerator</syntaxhighlight>]].
+
* and the special operator [[for-in loop#Declaring enumerators|<syntaxhighlight lang="delphi" inline>enumerator</syntaxhighlight>]].
The only operators that can not be overloaded are [[@|<syntaxhighlight lang="delphi" enclose="none">@</syntaxhighlight> (address operator)]], [[^|<syntaxhighlight lang="pascal" enclose="none">^</syntaxhighlight> (de-referencing operator)]], <syntaxhighlight lang="delphi" enclose="none">as</syntaxhighlight> and [[Is|<syntaxhighlight lang="delphi" enclose="none">is</syntaxhighlight>]].
+
The only operators that can not be overloaded are [[@|<syntaxhighlight lang="delphi" inline>@</syntaxhighlight> (address operator)]], [[^|<syntaxhighlight lang="pascal" inline>^</syntaxhighlight> (de-referencing operator)]], <syntaxhighlight lang="delphi" inline>as</syntaxhighlight> and [[Is|<syntaxhighlight lang="delphi" inline>is</syntaxhighlight>]].
  
== definition ==
+
== Definition ==
 
An operator is declared as if it was a [[Function|function]], with a few differences:
 
An operator is declared as if it was a [[Function|function]], with a few differences:
* Instead of the word <syntaxhighlight lang="pascal" enclose="none">function</syntaxhighlight> it starts with <syntaxhighlight lang="delphi" enclose="none">operator</syntaxhighlight>.
+
* Instead of the word <syntaxhighlight lang="pascal" inline>function</syntaxhighlight> it starts with <syntaxhighlight lang="delphi" inline>operator</syntaxhighlight>.
* The function's identifier is always one of the available operators e.g. <syntaxhighlight lang="pascal" enclose="none">><</syntaxhighlight>, although this would not constitute a valid identifier anywhere else. For compatibility reasons some of [[Delphi]]'s operator names are allowed, too (in fact, these are mandatory in mode Delphi):
+
* The function's [[Identifier|identifier]] is always one of the available operators e.&#8239;g. <syntaxhighlight lang="pascal" inline>><</syntaxhighlight>, although this would not constitute a valid identifier anywhere else. However, in <syntaxhighlight lang="pascal" inline>{$mode Delphi}</syntaxhighlight> a spelled out operator name ''has'' to be used. These are allowed in other modes, too (if the specific overload is allowed in a Delphi mode):
 
{| class="wikitable" style="margin: auto;"
 
{| class="wikitable" style="margin: auto;"
 
|+ Delphi compatibility operator names
 
|+ Delphi compatibility operator names
 
! operator symbol !! symbolic name
 
! operator symbol !! symbolic name
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">:=</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>:=</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">assign</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>implicit</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">+</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>+</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">add</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>add</syntaxhighlight>, <syntaxhighlight lang="delphi" inline>positive</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">-</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>-</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">subtract</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>negative</syntaxhighlight>, <syntaxhighlight lang="delphi" inline>subtract</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">*</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>*</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">multiply</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>multiply</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">div</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>div</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">intDivide</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>intDivide</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">mod</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>mod</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">modulus</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>modulus</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">/</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>/</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">divide</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>divide</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">=</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>=</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">equal</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>equal</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none"><></syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline><></syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">notEqual</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>notEqual</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none"><</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline><</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">lessThan</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>lessThan</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none"><=</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline><=</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">lessThanOrEqual</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>lessThanOrEqual</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">></syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>></syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">greaterThan</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>greaterThan</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">>=</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>>=</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">greaterThanOrEqual</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>greaterThanOrEqual</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">><</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>not</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">symmetricalDifference</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>logicalNot</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">not</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>and</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">logicalNot</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>logicalAnd</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">and</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>or</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">logicalAnd</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>logicalOr</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">or</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>and</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">logicalOr</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>bitwiseAnd</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">not</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>or</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">bitwiseNot</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>bitwiseOr</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">and</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>xor</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">bitwiseAnd</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>bitwiseXor</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">or</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>shl</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">bitwiseOr</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>leftShift</syntaxhighlight>
 
|-
 
|-
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">xor</syntaxhighlight>
+
| style="text-align:center;" | <syntaxhighlight lang="pascal" inline>shr</syntaxhighlight>
| <syntaxhighlight lang="delphi" enclose="none">bitwiseXor</syntaxhighlight>
+
| <syntaxhighlight lang="delphi" inline>rightShift</syntaxhighlight>
|-
 
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">shl</syntaxhighlight>
 
| <syntaxhighlight lang="delphi" enclose="none">leftShift</syntaxhighlight>
 
|-
 
| style="text-align:center;" | <syntaxhighlight lang="pascal" enclose="none">shr</syntaxhighlight>
 
| <syntaxhighlight lang="delphi" enclose="none">rightShift</syntaxhighlight>
 
 
|}
 
|}
* The parameter list has to name exactly one or two parameters, depending on the operator.
+
: Note, <syntaxhighlight lang="pascal" inline>><</syntaxhighlight>, <syntaxhighlight lang="delphi" inline>**</syntaxhighlight> and the bitwise <syntaxhighlight lang="pascal" inline>not</syntaxhighlight> have no equivalent in Delphi, but the symbolic operator designation is allowed instead.
* A result identifier has to be specified in front of the colon separating the result type, but can be omitted where the special identifier <syntaxhighlight lang="pascal" enclose="none">result</syntaxhighlight> is available.
+
* The parameter list has to name exactly one or two parameters, depending on the operator. The first formal parameter always refers, if applicable, to the operand on the left-hand side.
* Note, the concept of “default parameters,” that means a [[Routine#default values|default value]] for a parameter, only applies to “real” functions. When an operator is used, e.g. in an [[expression]], you can not just skip naming an operand, hoping the compiler will insert “something”. Therefore, the concept of default parameter values does not apply to operator overloads.
+
* A result identifier has to be specified in front of the colon separating the result type, but can be omitted where the special identifier <syntaxhighlight lang="pascal" inline>result</syntaxhighlight> is available.
 +
* Comparisons ''have'' to yield a [[Boolean|<syntaxhighlight lang="pascal" inline>Boolean</syntaxhighlight> value]].
 +
* The “source” and “target” types of assignment operator overloads must differ.
 +
* Note, the concept of “default parameters,” that means a [[Routine#default values|default value]] for a parameter, only applies to “real” functions. When an operator is used, e.&#x202F;g. in an [[expression]], you can not just skip naming an operand, hoping the compiler will insert “something”. Therefore, the concept of [[Default parameter|default parameter]] values does not apply to operator overloads.
  
The following shows a valid operator declaration.
+
The following shows a valid operator declaration (in <syntaxhighlight lang="pascal" inline>{$mode Delphi}</syntaxhighlight> the <syntaxhighlight lang="pascal" inline>:=</syntaxhighlight> has to be replaced by <syntaxhighlight lang="delphi" inline>implicit</syntaxhighlight> and the declaration may only appear in the context of class or advanced record definitions).
 
<syntaxhighlight lang="delphi">
 
<syntaxhighlight lang="delphi">
 
operator := (x: myNewType) y: someOtherType;
 
operator := (x: myNewType) y: someOtherType;
Line 132: Line 130:
  
 
Some operator overloads are not allowed:
 
Some operator overloads are not allowed:
* [[User Changes 2.4.0#Overloading the assignment operator with a shortstring result|overloading <syntaxhighlight lang="pascal" enclose="none">shortstring</syntaxhighlight> assignments with lengths other than <syntaxhighlight lang="pascal" enclose="none">255</syntaxhighlight>]]
+
* [[User Changes 2.4.0#Overloading the assignment operator with a shortstring result|overloading <syntaxhighlight lang="pascal" inline>shortstring</syntaxhighlight> assignments with lengths other than <syntaxhighlight lang="pascal" inline>255</syntaxhighlight>]]
* As of 2019-01-20 in the future: [[User Changes Trunk#Operator overload + no longer allowed for dynamic arrays|<syntaxhighlight lang="pascal" enclose="none">+</syntaxhighlight> in conjunction with dynamic arrays]]
+
* [[User Changes 3.2#Operator overload + no longer allowed for dynamic arrays|<syntaxhighlight lang="pascal" inline>+</syntaxhighlight> in conjunction with dynamic arrays]] if <syntaxhighlight lang="delphi" inline>{$modeSwitch arrayOperators+}</syntaxhighlight> (since FPC 3.2)
* <syntaxhighlight lang="pascal" enclose="none">+</syntaxhighlight> and <syntaxhighlight lang="pascal" enclose="none">-</syntaxhighlight> in conjunction with enumeration types
+
* <syntaxhighlight lang="pascal" inline>+</syntaxhighlight> and <syntaxhighlight lang="pascal" inline>-</syntaxhighlight> in conjunction with enumeration types
  
== routing ==
+
== Routing ==
Which operator overload definition is chosen differs in many aspects how a function is chosen.
+
How an operator overload definition is chosen differs in many aspects how a function is chosen.
* The assignment operator <syntaxhighlight lang="pascal" enclose="none">:=</syntaxhighlight> is used for ''implicit'' typecasts.
+
* The assignment operator <syntaxhighlight lang="pascal" inline>:=</syntaxhighlight> is used for ''implicit'' typecasts. Everywhere, where a value has to be stored in memory, an implicit typecast may occur. Note, that ''calling'' a [[Routine|routine]] requires storing its parameters in memory, too, thus the parameter list might become subject of implicit typecasts as well, even though on the surface they are not part of an assignment statement.
* Unlike regular function overloads, assignment operator overloads are chosen by their result type.
+
* Unlike regular function overloads, assignment operator overloads are chosen ''by their result type''.
* Operator overloads can not be chosen explicitly by their [[Scope|scope]] they are defined in. Something like <syntaxhighlight lang="pascal" enclose="none">unitDefiningOverloads.+</syntaxhighlight> is not possible. The last operator definition ''always'' wins and this can not be changed.
+
* Operator overloads can not be chosen explicitly by their [[Scope|scope]] they are defined in. Something like <syntaxhighlight lang="pascal" inline>unitDefiningOverloads.+</syntaxhighlight> is not possible. The last operator definition ''always'' wins and this can not be changed.
 +
* Operator precedence remains as usual for all operator symbols. When defining operators for a new custom type from scratch, the <syntaxhighlight lang="pascal" inline>*</syntaxhighlight> will still bind stronger than the <syntaxhighlight lang="pascal" inline>+</syntaxhighlight>. The operator precedence system can not be altered. FPC does not support [[PXSC]]-style <syntaxhighlight lang="pascal" inline>priority</syntaxhighlight> clauses.
  
 
Operator overloads should be used with caution.
 
Operator overloads should be used with caution.
They potentially make it harder to identify problems, since it is not necessarily obvious a operator overload applies.
+
They potentially make it harder to identify problems, since it is not necessarily obvious that an operator overload applies.
  
== see also ==
+
== See also ==
 
* [https://www.freepascal.org/docs-html/ref/refch15.html chapter “Operator overloading” in the “Free Pascal Reference Guide”]
 
* [https://www.freepascal.org/docs-html/ref/refch15.html chapter “Operator overloading” in the “Free Pascal Reference Guide”]
 
* [https://en.wikipedia.org/wiki/Operator_overloading article “operator overloading” in the English Wikipedia]
 
* [https://en.wikipedia.org/wiki/Operator_overloading article “operator overloading” in the English Wikipedia]
 +
 +
[[Category:Pascal]]
 +
[[Category:FPC]]

Latest revision as of 08:05, 28 February 2024

English (en)

Operator overloading refers to re-defining already defined operators with new definitions. The term is – although imprecisely – used for operator definitions, that have not yet been defined, too.

Availability

The FPC supports PXSC-style operator overloading, however it is not allowed in {$mode TP} or {$mode MacPas}. In {$mode Delphi}, operator overloading can only be done in the context of classes or advanced records (confer Delphi documentation), so the Delphi mode does not support global operator overloads as {$mode FPC} and {$mode objFPC} do.

Overloadable operators

Almost all operators can be (re-)defined:

  • assignment operators
    • :=
    • the special operator explicit (referring to explicit typecasts)
  • arithmetic operators
    • + (only binary operation)
    • - (both unary and binary)
    • *
    • **
    • div
    • mod
    • /
    • inc
    • dec
    • (As of 2020 in the future: pow)
  • comparison operators
  • logical operators
  • and the special operator enumerator.

The only operators that can not be overloaded are @ (address operator), ^ (de-referencing operator), as and is.

Definition

An operator is declared as if it was a function, with a few differences:

  • Instead of the word function it starts with operator.
  • The function's identifier is always one of the available operators e. g. ><, although this would not constitute a valid identifier anywhere else. However, in {$mode Delphi} a spelled out operator name has to be used. These are allowed in other modes, too (if the specific overload is allowed in a Delphi mode):
Delphi compatibility operator names
operator symbol symbolic name
:= implicit
+ add, positive
- negative, subtract
* multiply
div intDivide
mod modulus
/ divide
= equal
<> notEqual
< lessThan
<= lessThanOrEqual
> greaterThan
>= greaterThanOrEqual
not logicalNot
and logicalAnd
or logicalOr
and bitwiseAnd
or bitwiseOr
xor bitwiseXor
shl leftShift
shr rightShift
Note, ><, ** and the bitwise not have no equivalent in Delphi, but the symbolic operator designation is allowed instead.
  • The parameter list has to name exactly one or two parameters, depending on the operator. The first formal parameter always refers, if applicable, to the operand on the left-hand side.
  • A result identifier has to be specified in front of the colon separating the result type, but can be omitted where the special identifier result is available.
  • Comparisons have to yield a Boolean value.
  • The “source” and “target” types of assignment operator overloads must differ.
  • Note, the concept of “default parameters,” that means a default value for a parameter, only applies to “real” functions. When an operator is used, e. g. in an expression, you can not just skip naming an operand, hoping the compiler will insert “something”. Therefore, the concept of default parameter values does not apply to operator overloads.

The following shows a valid operator declaration (in {$mode Delphi} the := has to be replaced by implicit and the declaration may only appear in the context of class or advanced record definitions).

operator := (x: myNewType) y: someOtherType;

Operators are defined the same way as any other function, by following the signature with a block.

Some operator overloads are not allowed:

Routing

How an operator overload definition is chosen differs in many aspects how a function is chosen.

  • The assignment operator := is used for implicit typecasts. Everywhere, where a value has to be stored in memory, an implicit typecast may occur. Note, that calling a routine requires storing its parameters in memory, too, thus the parameter list might become subject of implicit typecasts as well, even though on the surface they are not part of an assignment statement.
  • Unlike regular function overloads, assignment operator overloads are chosen by their result type.
  • Operator overloads can not be chosen explicitly by their scope they are defined in. Something like unitDefiningOverloads.+ is not possible. The last operator definition always wins and this can not be changed.
  • Operator precedence remains as usual for all operator symbols. When defining operators for a new custom type from scratch, the * will still bind stronger than the +. The operator precedence system can not be altered. FPC does not support PXSC-style priority clauses.

Operator overloads should be used with caution. They potentially make it harder to identify problems, since it is not necessarily obvious that an operator overload applies.

See also