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