Delphi. What is difference to TProcedure, TMethod = procedure of object and TAnonMethod = reference to procedure ?

Source

Let us consider the following three type declarations:

TProcedure = procedure;
TMethod = procedure of object;
TAnonMethod = reference to procedure;

These are all very similar to each other. In terms of calling instances of each of these three types, the calling code is identical. The differences arise in what can be assigned to variables of these types.

Procedural types

TProcedure is a procedural type. You can assign to a variable of type TProcedure something of this form:

procedure MyProcedure;
begin
end;

This is a non object-oriented procedure. You cannot assign an instance or class method to a TProcedure variable. However, you can assign a static class method to a TProcedure variable.

Method pointers

TMethod is a method pointer. This is indicated by the presence of of object. When you have a variable of type TMethod you must assign either:

  1. A instance method of an instantiated object, or
  2. A class method.

So you can assign either of these:

procedure TMyClass.MyMethod;
begin
end;

class procedure TMyClass.MyClassMethod;
begin
end;

The big difference between a procedural type and a method pointer is that the latter contains a reference to both code and data. A method pointer is often known as a two-pointer procedural type. A variable that contains a method pointer contains references to the code and the instance/class to call it on.

Consider the following code:

var
  instance1, instance2: TMyClass;
  method1, method2: TMethod;
....
method1 := instance1.MyMethod;
method2 := instance2.MyMethod;

Now, although method1 and method2 refer to the same piece of code, they are associated with different object instances. So, if we call

method1();
method2();

We are invoking MyMethod on the two distinct instances. That code is equivalent to:

instance1.MyMethod();
instance2.MyMethod();

Anonymous methods

Finally we come to anonymous methods. These are even more general purpose than procedural types and method pointers. You can assign any of the following to a variable defined using the reference to syntax:

  1. A plain non object-oriented procedure.
  2. An instance method of an instantiated class.
  3. A class method.
  4. An anonymous method.

For example:

var
  AnonMethod: TAnonMethod;
....
AnonMethod := MyProcedure;            // item 1 above
AnonMethod := instance1.MyMethod;     // item 2
AnonMethod := TMyClass.MyClassMethod; // item 3

Anonymous methods, item 4 above, are those declared in-line in your code. For example:

var
  AnonMethod: TAnonMethod;
....
AnonMethod := procedure
  begin
    DoSomething;
  end;

The biggest benefit of anonymous methods when compared to the procedural types and method pointers is that they allow for variable capture. For example consider the following short program to illustrate:

{$APPTYPE CONSOLE}
program VariableCapture;

type
  TMyFunc = reference to function(X: Integer): Integer;

function MakeFunc(Y: Integer): TMyFunc;
begin
  Result := function(X: Integer): Integer
    begin
      Result := X*Y;
    end;
end;

var
  func1, func2: TMyFunc;

begin
  func1 := MakeFunc(3);
  func2 := MakeFunc(-42);
  Writeln(func1(4));
  Writeln(func2(2));
  Readln;
end.

This has the following output:

12
-84
This entry was posted in Без рубрики. Bookmark the permalink.