[fpc-devel] Delphi anonymous methods

Sven Barth pascaldragon at googlemail.com
Mon Mar 4 14:29:28 CET 2013


Am 04.03.2013 01:15, schrieb Graeme Geldenhuys:
> On 2013-03-02 19:03, vrt277 wrote:
>> I want to implement support of Delphi anonymous methods for fpc.
>
> Just curious... why must such a feature be allowed in Object Pascal?
> Referring to the recent "butchering of the Object Pascal language"
> thread we had recently in fpc-pascal.

You should not look only at the syntax (after all I'm not a big fan of 
the syntax either, but I definitely support the feature). Look behind it 
and see what it provides. The most important concept of anonymous 
functions is the closure concept. That the function can capture the 
content of local variables and extend their lifetime past the lifetime 
of the function where it was originally defined.

E.g. (and please ignore the syntax!)

=== example begin ===

type
   TMyFunc = reference to function(aArg: Integer): String;

function GetFunction: TMyFunc;
var
   someintf: ISomeInterface;
   s: String;
begin
   someintf := TSomeInterfaceImpl.Create;
   s := someintf.GetSomeString;
   Result := function(aArg: Integer): String
                   begin
                      Result := someintf.SomeFunc(aArg) + s;
                   end;
end;

// somewhere else
var
   f: TMyFunc;
begin
   f := GetFunction;
   Writeln(f(42));
end;

=== example end ===

The "s" and the "someintf" will exist until the "f" variable goes out of 
scope ("reference to" procvars use rerence counting).

Also in the context of threading anonymous methods can be considered a 
nice alternative. First there is the point of Synchronize:

The way that currently needs to be done with FPC and older Delphi versions:

=== example begin ===

type
   TMyThread = class(TThread)
   private
     fAddText: String;
     procedure AddTextSync;
   protected
     procedure Execute; override;
   end;

procedure TMyThread.AddTextSync;
begin
   // normally one should use an event or something, but we'll just 
directly access the GUI here
   fMyForm.Memo.Lines.Add(fAddText);
end;

procedure TMyThread.Execute;
begin
   //...
   fAddText := 'Step 42';
   Synchronize(@AddTextSync);
   //...
end;

=== example end ===

With anonymous functions:

=== example begin ===

type
   TMyThread = class(TThread)
   protected
     procedure Execute; override;
   end;

procedure TMyThread.Execute;
begin
   //...
   Synchronize(
     procedure
     begin
       fMyForm.Memo.Lines.Add('Step 42');
     end;
   );
   //...
end;

=== example end ===

With the proposed lambda syntax from another recent thread:

=== example begin ===

type
   TMyThread = class(TThread)
   protected
     procedure Execute; override;
   end;

procedure TMyThread.Execute;
begin
   //...
   Synchronize(lambda TProc as fMyForm.Memo.Lines.Add('Step 42'));
   //...
end;

=== example end ===

Also the new extensions of the TThread-API brought another nice gimmick:

=== example begin ===

// fire and forget something :)
TThread.CreateAnonymousThread(procedure
   begin
     SomeThingThatShouldBeDoneParallel;
   end
   ).Start;

=== example end ===

Some of the things could be implemented by allowing "is nested" procvars 
additionally to normal procvars or "of object" procvars (e.g. for 
TThread.Synchronize and TThread.Queue). But what is not trivially to 
implement with current features of FPC is the closure aspect. The 
resulting code would more ugly than even a really fat anonymous function.

Again: I'm not a supporter of the anonynmous function syntax. But I 
support the semantic behind it. Which is why I wanted to have closures 
supported through nested functions/procedures in non-Delphi modes. [And 
I'd also like a lambda syntax for simple cases, e.g. one 
statement/expression]

Regards,
Sven



More information about the fpc-devel mailing list