On 03/05/2013 05:34 AM, waldo kitty wrote:
It is as I thought about closures before. But this is useless without capturing of variables by value. During creation of anonymous method you *can not bind any values* to it. Anonymous method have only references to captured variables. Pascal don't allows to create static variables inside function like in c-like languages. So you also not able to create unique static variable which available only to one instance of same anonymous method. Even if implementation will create many separate objects for one anonymous function then all instances will
be equivalent. Because all instances will refer to same data.

i'm trying to understand what you mean by

> Pascal don't allows to create static variables inside function like in c-like
> languages.

i've done something that i think is what you speak of but it was in Borland's Turbo Pascal... at least TP6... i don't remember how we did it though and can't find any sample code in my library :(

what happened is that the value did not get cleared between invocations of the routine and subsequent executions could use the value already stored... this breaks, of course, if the memory area for the routine is cleared first...

_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel
Word "static" is mistake here, sorry. It should be "local" variable instead.
As it was said in this thread: closure is a way to create object (no mean named closure or anonymous). Closure is a routine with all variables which it accesses (or "captures" in terminology of Delphi or C++). So closure is routine + captured data. I expected that Delphi will create one object for one closure. In example below I was expecting to see creation of 10 different objects. But Delphi creates only 1 object. I was surprised.

=== example
for i := 1 to 10 begin
    arr[i] := procedure begin
                     ...
                 end;
===
All arr[i] have same value(same reference).

Actually Delphi creates object(called FrameObject in Delphi's docs) for closure otherwise it will not work. But Delphi creates this object not for every closure but only for procedure where closure defined. This details described in pdf file which I attached in first message of thread. Also Sven created good comments which describes how Delphi implements closures and how capturing by value should work http://lists.freepascal.org/lists/fpc-devel/2013-March/031588.html.

My confused comment can be reformulated: Delphi doesn't create object for each closure because there is no need to do it. But why many other languages should create object for each closure but Delphi need not ? Because Pascal allows to declare local variables only in beginning of routine. But many c-like languages allows to declare local variables in middle of routine. I will describe on example.

Imagine that you want to create many similar objects in loop like this:

=== example

type TWriter = class
       data: Integer;
       constructor Create(i: Integer);
       procedure Execute;
     end;
constructor TWriter.Create(i: Integer); begin data := i; end;
procedure TWriter.Execute; begin Writeln(data); end;

var i: Integer;
    arr: array[1..10] of TWriter;
begin
  for i := 1 to 10 do
    arr[i] := TWriter.Create(i);
  for i := 1 to 10 do
    arr[i].Execute;
end.
===

=== output
1 2 3 4 5 6 7 8 9 10
===

If someone will try to make same trick using Delphi's anonymous methods(Delphi's implementation of closures) he may try to do this

=== wrong

  for i := 1 to 10 do
    procArr[i] := procedure begin
                    Writeln(i);
                  end;

  for j := 1 to 10 do
    procArr[j]();
===

=== output
11 11 11 11 11 11 11 11 11 11
===

Why? Because all procedures from procArr captured variable 'i' by reference. They access same variable. So this is a problem to simply create "private" data for closure. But you can do it like this:

=== right

function Factory(data: Integer): TProc;
begin
  Result := procedure begin
              Writeln(data);
            end;
end;

...

  for i := 1 to 10 do
    procArr[i] := Factory(i);
  for j := 1 to 10 do
    procArr[j]();

===

=== output
1 2 3 4 5 6 7 8 9 10
===

Just as expected.
Now about local variables and why in other languages simple creation of "private" variable for closure is not a problem.

=== perl
for (my $i = 0; $i < 10; ++$i) {
    {
        my $stored = $i;
        $f[$i] = sub { printf $stored }
    }
}

for (my $j = 0; $j < 10; ++$j) {
    $f[$j]();
}
===

=== output
0123456789
===

This is works because:
  - each loop iteration creates new variable $stored
  - closure captures $stored
- variable $stored is accessible only in it's declaring block { .. } ; at end of loop iteration only closure will save link to it.

So Perl have to create new object for each closure because each closure may contains private data. In Delphi closures also can have private data, but closures created in same function will capture same data. Closures created in same line of code will not only refer to same data but also will have same behaviour. That is why in 1st example of my email Delphi all elements of arr are equal.

Vasiliy K.




_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to