Anonymous procedures (Was: Re: [fpc-devel] for-in-index loop)

Alexander Klenin klenin at gmail.com
Fri Jan 25 23:57:04 CET 2013


On Sat, Jan 26, 2013 at 5:17 AM, Sven Barth <pascaldragon at googlemail.com> wrote:
> One could also do an alternative (though currently not with arrays, but with
> type helper support even that would be possible...):

Yes, this is certainly the most interesting alternative. Actually,
anonymous procedures/closures
is the "real" task I wanted Vasily to perform, after the "warm-up" of
for-in-index.
I am still of the opinion that "for-in-index" would be a good addition
nevertheless,
because it is a simple and neat solution for 90% of the cases, so even
if there exists
a general and complex solution for 100%, IMHO simple one is still worth having.

Nevertheless, I separated the thread to discuss anonymous procedures,
hopefully with less flame, or at least, with flame of different colours :)

When comparing anonymous procedures with built-in for-in loop,
it is important to consider the code speed.
I think that good support for inlining "Iterate" procedure *together
with its argument*
is essential for anonymous procedures to be a competitive solution for
the problem
of container iteration.

>   map.Iterate(procedure(const aKey: String; const aValue: TObject)
>     begin
>       Writeln(aKey, ' => ', aValue.ClassName);
>     end;
>   );

As you noted, this solution is conceptually good, but rather cumbersome to write

You have also proposed lambda-expressions:
>map.Iterate(lambda TFPGMapLongInt.TIteratorProc(aKey, aData) as Writeln(aKey, ' => ', aData.ClassName));

I think that they are not optimal in the proposed form.
Note that the longest part of the expression is actually a restatement
of the Iterate parameter type.
I propose to allow omitting that:

map.Iterate(lambda begin
  Writeln(aKey, ' => ', aData.ClassName);
end;)

That is, basically, "lambda" means "use procedure definition from the
parameter type".

Independently, I propose a general shorthand for functions containing
a single expression
(and perhaps for procedures containing a single statement, but I am
less certain here):

function f(a, b: Integer): Integer;
begin Result := a + b; end;
=>
function f(a, b: Integer): Integer as a + b;

with both shortcuts combined, it becomes possible to write something like

sum := arr.Reduce(lambda as a + b;);

Even further, Ruby (or Objective C)-like extension may be introduced to allow
procedure arguments (or perhaps just the last one) to be separated by
some special character instead of parenthesis, for example:
procedure p(a, b: Integer);
p(3, 5); // Traditional syntax
p :3 :5; // Proposed extension
Then, then code will be

map.Iterate :lambda
  Writeln(aKey, ' => ', aData.ClassName);
end;

sum := arr.Reduce :lambda as a + b;

which is as good as it gets, IMHO.

> And for a given array type and type helper support you can do the following:
While type helpers are a neat idea, I fear they introduce too much
"action at a distance"
for so frequent usage.
A global generic functions (they are planned anyway, aren't they?)
will be sufficient:

Iterate :map :lambda
  Writeln(aKey, ' => ', aData.ClassName);
end;

--
Alexander S. Klenin



More information about the fpc-devel mailing list