Barry Kelly has explained in his recent post how to obtain a method pointer from an anonymous method. Here I will play a little more with the anonymous methods (using Delphi 2009) and consider a somewhat reversed problem – how to create an anonymous method that incapsulates the ordinary function.
First how it is done in the “normal” way:
type TIntFunc = function(Value: Integer): Integer; TIntFuncRef = reference to function(Value: Integer): Integer; function Square(Value: Integer): Integer; begin Result:= Value * Value; end; function MakeAnonMethod(AFunc: TIntFunc): TIntFuncRef; begin Result:= function(Value: Integer): Integer begin Result:= AFunc(Value); end; end; procedure TForm1.Button1Click(Sender: TObject); var AnonMethod: TIntFuncRef; begin AnonMethod:= MakeAnonMethod(@Square); ShowMessage(IntToStr(AnonMethod(2))); end;
The MakeAnonMethod function creates the anonymous method that captures a function variable (AFunc argument, actually a pointer). That is simple.
Now let us consider what is going on behind the scene. An anonymous method is internally an interface with a single method “Invoke”:
type TAnonCaller = class(TInterfacedObject, TIntFuncRef) private FFunc: TIntFunc; function Invoke(Value: Integer): Integer; public constructor Create(AFunc: TIntFunc); end; constructor TAnonCaller.Create(AFunc: TIntFunc); begin FFunc:= AFunc; end; function TAnonCaller.Invoke(Value: Integer): Integer; begin Result:= FFunc(Value); end; procedure TForm1.Button2Click(Sender: TObject); var AnonMethod: TIntFuncRef; begin AnonMethod:= TAnonCaller.Create(@Square); ShowMessage(IntToStr(AnonMethod(2))); end;
The second code snippet do the same thing as the first – it “captures” the function variable in TAnonCaller.Create constructor and uses it to call the “captured” function.
The above code snippets show that
- when we create an anonymous method we actually create an object that implements an interface of a special kind and obtain a reference to the interface
- when we call the anonymous method we actually call the Invoke method of the interface.
The above is an oversimplified description of how the anonymous methods work internally. A more closer look at anonymous methods shows that several anonymous methods may share a single object implementing the interfaces for all of them, and that is the way how the different anonymous methods share the captured variables (as fields of the common object).
You don’t need to do that. This line will work just as well:
AnonMethod := Square;
Method references are designed to be assignment compatible on input with methods, functions, method pointers, function pointers and anonymous methods.
Thank you for the remark – nice feature.