Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
671 views
in Technique[技术] by (71.8m points)

delphi - Anonymous methods - variable capture versus value capture

Below is a SSCCE based on an example in the Anonymous Methods section of Part 1 of Chris Rolliston's excellent Delphi XE2 Foundations book, about the idea of variable capture (any errors in it are entirely down to me).

It works exactly as I'd expect, logging 666, 667, 668, 669 on successive clicks of the BtnInvoke button. In particular it nicely illustrates how the captured version of the local variable I persists long after btnSetUpClick exits.

So far so good. The problem I'm asking about isn't with this code per se but with what's said in Allen Bauer's blog here:

http://blogs.embarcadero.com/abauer/2008/10/15/38876

Now, I know better than to argue with the boss, so I am sure I'm missing the point of the distinction he draws between variable capture and value capture. To my simple way of looking at it, my CR-based example captures the value of I by capturing I as a variable.

So, my question is, what is the distinction Mr Bauer is trying to draw, exactly?

(Btw, despite watching the Delphi section of SO daily for 9+ months, I'm still not entirely clear if this q is on-topic. If not, my apologies and I'll take it down.)

type
  TAnonProc = reference to procedure;

var
  P1,
  P2 : TAnonProc;

procedure TForm2.Log(Msg : String);
begin
  Memo1.Lines.Add(Msg);
end;

procedure TForm2.btnSetUpClick(Sender: TObject);
var
  I : Integer;
begin
  I := 41;
  P1 := procedure
    begin
      Inc(I);
      Log(IntToStr(I));
    end;

  I := 665;
  P2 := procedure
    begin
      Inc(I);
      Log(IntToStr(I));
    end;
end;

procedure TForm2.btnInvokeClick(Sender: TObject);
begin
  Assert(Assigned(P1));
  Assert(Assigned(P2));

  P1;
  P2;
end;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Variable capture vs value capture is simple enough. Let us suppose that two anonymous methods capture the same variable. Like this:

Type
  TMyProc = reference to procedure;
var
  i: Integer;
  P1, P2: TMyProc;
....
i := 0;
P1 := procedure begin Writeln(i); inc(i); end;
P2 := procedure begin Writeln(i); inc(i); end;
P1();
P2();
Writeln(i);

There is a single variable that is captured by both methods. The output is:

0
1
2

This is capture of a variable. If the value was captured, which it isn't, one might imagine that the two methods would have separate variables that both started with value 0. And both functions might output 0.

In your example, you are supposed to imagine that P1 captures the value 41, and P2 captures the value 665. But that does not happen. There is exactly one variable. It is shared between the procedure that declares it, and the anonymous methods that capture it. It lives as long as all parties that share it live. Modifications to the variable made by one party are seen by all others because there is exactly one variable.


So, it is not possible to capture a value. To get behaviour that feels like that you need to copy a value to a new variable, and capture that new variable. That can be done with, for instance, a parameter.

function CaptureCopy(Value: Integer): TMyProc;
begin
  Result := procedure begin Writeln(Value); end;
end;

...
P3 := CaptureCopy(i);

This will copy the value of i into a new variable, the procedure parameter, and capture that. Subsequent changes to i have no influence on P3 because the captured variable is local to P3.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...