While reading the documentation at Anonymous Methods in Delphi I started to wonder. I've always used something like this:
type TMathFn = Function(A, B: Integer): Integer;
var fn: TMathFn;
Always worked for me. But this document tells me to use this instead:
type TMathFn = Reference to Function(A, B: Integer): Integer;
var fn: TMathFn;
And as I've been developing in Delphi from 1994 until 2010 I'm a bit unfamiliar with this "Reference to" part. Still, both options seem to work identically. So...
Are they identical?
"REFERENCE TO" is to allow Anonymous Methods (inline definitions of PROCEDUREs/FUNCTIONs), which can Capture a context (for example local variables, which are captured as references, ie. if you change the variable after capture, it's the modified value that is captured, see below).
TYPE TMyProc = REFERENCE TO PROCEDURE(CONST S : STRING);
PROCEDURE Information(CONST S : STRING);
BEGIN
MessageDlg(S,mtInformation,[mbOK],0)
END;
PROCEDURE RunProc(P : TMyProc ; CONST S : STRING);
BEGIN
P(S)
END;
PROCEDURE A(B,C : INTEGER);
VAR
D : INTEGER;
P : TMyProc;
BEGIN
D:=3;
// D is 3 at the time of capture
P:=PROCEDURE(CONST S : STRING)
BEGIN
Information(S+': '+IntToStr(D)+' -> '+IntToStr(B))
END;
// D is now 4 - and is reflected in the captured routine, as
// the capture is done by REFERENCE and not by VALUE.
INC(D);
RunProc(P,'Hello')
END;
BEGIN
A(2,3)
END.
Will show "Hello: 4 -> 2" in a message box.
The above definition of P "captures" (includes) the variables D and B so that even if you pass it to another function, where these variables don't exist, you can still access them.
This would be (nearly) impossible to do with ordinary PROCEDURE [OF OBJECT] types, as they can't access local variables declared at the point of execution.
No, they are not identical.
The difference is that
TMathFn = function(A, B: Integer): Integer;
is an ordinary function,
TMathMethod = function(A, B: Integer): Integer of object;
is a method, and
TMathAnonMethod = reference to function(A, B: Integer): Integer;
is an anonymous method, but you can also assign an ordinary function or a method to a variable of this type.
So, for instance, if
type
TMathFn = function(A, B: Integer): Integer;
TMathMethod = function(A, B: Integer): Integer of object;
TMathAnonMethod = reference to function(A, B: Integer): Integer;
function Test(A, B: Integer): Integer;
begin
Result := A + B;
end;
type
TTestClass = class
function Test(A, B: Integer): Integer;
end;
{ TTestClass }
function TTestClass.Test(A, B: Integer): Integer;
begin
Result := A + B;
end;
then the following applies:
procedure TForm1.FormCreate(Sender: TObject);
var
T: TTestClass;
F: TMathFn;
M: TMathMethod;
AM: TMathAnonMethod;
begin
T := TTestClass.Create;
try
F := Test; // compiles
F := T.Test; // doesn't compile
F := function(A, B: Integer): Integer
begin
Result := A + B;
end; // doesn't compile
M := Test; // doesn't compile
M := T.Test; // compiles
M := function(A, B: Integer): Integer
begin
Result := A + B;
end; // doesn't compile
AM := Test; // compiles
AM := T.Test; // compiles
AM := function(A, B: Integer): Integer
begin
Result := A + B;
end; // compiles
finally
T.Free;
end;
end;
Under the hood, as you probably already know, F
is simply a (function) pointer and M
is a method pointer. Anonymous methods, on the other hand, have a more involved interface-based implementation, which allows all their magic (like variable capture).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With