Operator

From Free Pascal wiki

Deutsch (de) English (en) suomi (fi)
An operator is a special kind of function. It can be invoked by placing keywords adjacent to suitable operands.

The word operator colloquially refers to the symbol or keyword identifying the function that implements the actual operation. operator is also a reserved word that appears in the course of operator overloading.

usage

Most operators are binary, that means require two operands. Binary operator symbols appear between two operands, like this:

x + 5

The plus character identifies the addition operation (Standard Pascal). x and 5 are its operands. This style is called infix notation.

Unary operators – those which require only one operand – appear in front of their operands (prefix notation), with the exception of ^, the de-referencing operator, which appears after its operand (postfix notation). Example:

-x

Here, the minus character identifies the sign inversion operation (Standard Pascal). Blanks between operator and operand do not harm, confer the following section regarding precedence. However, it is common practice to place unary operator symbols back to back with their operands.

Operator symbols always appear explicitly, except the implicit typecast and enumerator operator. Unlike in mathematics, no invisible “times” is assumed between two identifiers.

Implicit typecasts occur, where a value has to be stored in a memory location. Note, that calling a routine triggers implicit typecasts, too. In order to pass the parameters to the routine, they are stored somewhere. Implicit typecasts are not limited to run-of-the-mill assignment statements.

operator precedence

Operands and operators are the building blocks of expressions. The use of operators is a powerful notational tool, since LOCs do not get cluttered by function calls consisting of function identifiers and parentheses, but instead the operands and (ideally) a short symbol achieve the same. Instead of, for example, sum(x, -8) the expression x - 8 evaluates to the same value, while writing five less characters.

In order to increase conciseness subexpressions of expressions propagate their intermediate result in a predefined hierarchy. This hierarchy can be superseded by placing parentheses ( ) around subexpressions that shall be treated as one expression, so the regular precedence rules apply in the enclosed part remaining uninfluenced from the expression's rest. Operators that have have higher precedence, bind to operands stronger.

operator precedence
precedence operators category
highest
(first)
  • not (both, logical and bitwise variant)
  • unary + (sign identity, “positive sign”)
  • unary - (sign inversion, “negative sign”)
  • **
  • pow
  • @
  • ^ (de-referencing operator)
  • explicit typecasts
  • unary operators (except
    destination-dependent operators)
  • power
second
  • *
  • and (both, logical and bitwise variant)
  • and_then
  • /
  • div
  • mod
  • shl (<<)
  • shr (>>)
  • as
  • multiplication operators
  • conditional typecast
third
  • +
  • -
  • or (both, logical and bitwise variant)
  • or_else
  • xor (both, logical and bitwise variant)
  • addition operators
  • complex logical operators
fourth
  • <
  • >
  • =
  • <>
  • <= (both, ⊆ as well as ≤)
  • >=
  • in
  • ><
  • is
  • relational operators
  • inheritance test
lowest
(last)
  • destination-dependent conversions

) This symbol does not refer to an actual operator, but is (imprecisely) called as one.

Inc and dec are pseudo operators: They may be redefined via the operator overloading mechanism, but they can not appear in expressions, like any function could. Therefore their precedence is moot.

Include and exclude are also not operators, but shorthand for common LOCs.

@ and ^ albeit being called operators, are not operators, but rather instruct the compiler to interpret an identifier differently than usual. This is not done via any function, but compiler intrinsics.

evaluation order

Note-icon.png

Note: Operator precedence does not infer evaluation order. The compiler may re-arrange expressions according to associative and commutative properties of operators.

No assumptions shall be made, and there is no guarantee, that expressions are evaluated from left to right (or the reverse direction). The FPC for instance, evaluates more “complex” subexpressions first before moving on to “trivial” parts (ratio: avoiding register spilling).

If a subexpression has to be evaluated first, e.g. a function triggering some side-effects, the expression has to be split up into two separate statements. For example:

x := foo() + bar();

The compiler may evaluate foo() or bar() first. If bar() ought to be evaluated first at all events, the statement has to be split into two separate ones:

x := bar();
x := x + foo();


Note-icon.png

Note: The compiler directive {$boolEval off} enables “lazy” evaluation. Parts of expressions may not be evaluated at all.

see also