Anonymous methods - second administration by Radek Červinka

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Anonymous methods - second administration by Radek Červinka
Radek Červinka - 16/Jan/2015
[SHOWTOGROUPS=4,20]
At the time of Delphi 2009 release, I described Anonymous methods (sometimes in other languages as closure), but somehow I did not realize the main, resp. somehow I did not understand the importance of one property and that is "capture", ie capturing the state of local variables, which is fundamentally different from the type of function or method.

Let's have the following code next to the form. We have two anonymous ones that have the same parameters, but one is declared as a new type, the other uses a generic declaration of the anonymous method from sysutils (to make it clear that generics are not just collections and sheets).
Код:
// SysUtils: TProc<T1,T2> = reference to procedure (Arg1: T1; Arg2: T2);

So at the beginning in formcreate both references are emptied, one button sets them, the other calls them.
Код:
type
  TRefIntProc = reference to procedure(const sVal: string; iAdd: Integer);

  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    FIntProc : TRefIntProc;
    FIntProc2: TProc<string, Integer>;
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  i := 3;
  // nastav první anonymní metodu
  FIntProc := procedure(const sVal: string; iAdd: Integer)
    begin
      inc(i, iAdd);
      ShowMessage(sVal + ' IntProc:' + IntToStr(i));
    end;
  // a druhou
  FIntProc2 := procedure(sVal: string; iAdd: Integer)
    begin
      inc(i, iAdd);
      ShowMessage(sVal + ' IntProc2:' + IntToStr(i));
    end;
  inc(i); // 4
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  if assigned(FIntProc) then
    FIntProc('Button2Click', 4);
  if assigned(FIntProc2) then
    FIntProc2('Button2Click', 3);
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  FIntProc  := nil;
  FIntProc2 := nil;
end;

Please note in Button1Click operation work with variable "i" , for sure "i = 4" at the end of operation. Anonymous methods are assigned at the moment when "i = 3".
In the Button2Click handler, a call to both stored methods is made (via assigned, if it occurred to someone to call before Button1).
Review question: What happens after the first and second clicks?

For the solution, it is necessary to understand that assigning an anonymous method will cause local variables to be captured and live as long as the anonymous method. It is solved somehow through interfaces and reference counting, so that local variables are copied, including parameters, and they live on, and the anonymous method continues to work with them.

I.e. after clicking it will be displayed
Код:
Button2Click IntProc:8
[OK]

Button2Click IntProc2:11
[OK]

After another click, the values change to 15 and 18.

Now it is clear that what I wrote is true and the local variable is stored somewhere and the anonymous method can work with it. In my opinion, this preservation of the state is an important and interesting feature for later use.

Last time I wrote that I understand a lot of power in synchronizations such as GUI. I recommended using them for synchronization, but somehow I forgot
Код:
TThread.Queue(AThreadProc: TThreadProcedure)

which is an asynchronous synchronization of the UI in the main thread.

Regardless of their use due to parallel programming.
[/SHOWTOGROUPS]