Procedural Types in Statements and Expressions
When a procedural variable is on the left side of an assignment statement, the compiler expects a procedural value
on the right. The assignment makes the variable on the left a pointer to the function or procedure indicated on the
right. In other contexts, however, using a procedural variable results in a call to the referenced procedure or function.
You can even use a procedural variable to pass parameters:
var
F: function(X: Integer): Integer;
I: Integer;
function SomeFunction(X: Integer): Integer;
...
F := SomeFunction; // assign SomeFunction to F
I := F(4); // call function; assign result to I
In assignment statements, the type of the variable on the left determines the interpretation of procedure or method
pointers on the right. For example,
var
F, G: function: Integer;
I: Integer;
91
function SomeFunction: Integer;
...
F := SomeFunction; // assign SomeFunction to F
G := F; // copy F to G
I := G; // call function; assign result to I
The first statement assigns a procedural value to
F
. The second statement copies that value to another variable.
The third statement makes a call to the referenced function and assigns the result to
I
. Because
I
is an integer
variable, not a procedural one, the last assignment actually calls the function (which returns an integer).
In some situations it is less clear how a procedural variable should be interpreted. Consider the statement
if F = MyFunction then ...;
In this case, the occurrence of
F
results in a function call; the compiler calls the function pointed to by
F
, then calls
the function
MyFunction
, then compares the results. The rule is that whenever a procedural variable occurs within
an expression, it represents a call to the referenced procedure or function. In a case where
F
references a procedure
(which doesn't return a value), or where
F
references a function that requires parameters, the previous statement
causes a compilation error. To compare the procedural value of
F
with
MyFunction
, use
if @F = @MyFunction then ...;
@F
converts
F
into an untyped pointer variable that contains an address, and
@MyFunction
returns the address of
MyFunction
.
To get the memory address of a procedural variable (rather than the address stored in it), use @@. For example,
@@F
returns the address of
F
.
The @ operator can also be used to assign an untyped pointer value to a procedural variable. For example,
var StrComp: function(Str1, Str2: PChar): Integer;
...
@StrComp := GetProcAddress(KernelHandle, 'lstrcmpi');
calls the
GetProcAddress
function and points
StrComp
to the result.
Any procedural variable can hold the value nil, which means that it points to nothing. But attempting to call a nil-
valued procedural variable is an error. To test whether a procedural variable is assigned, use the standard function
Assigned
:
if Assigned(OnClick) then OnClick(X);
92
|