[fpc-devel] Delphi anonymous methods

Martin lazarus at mfriebe.de
Mon Mar 4 21:47:58 CET 2013


On 04/03/2013 19:16, Alexander Klenin wrote:
>>>     function NAME(PARAMS): RETURNTYPE as EXPRESSION
>> IMHO that is not a good idea. It adds an additional construct, that every
>> reader must know how to read. It does not add/save enough to be needed.
> I agree, it is borderline, and needs to be additionally justified.
> I believe that for each feature, there is a threshold for the baroqueness of
> syntax required to use it which separates "obscure" from "simple and
> understandable".
> The main barrier for understanding code is not actually the number of
> language constructs involved -- they are way too few compared to,
> say, number of procedures in any non-trivial library.
> The main barrier is the amount of effort required to see the programmers intent
> while looking at a given piece of code.
> For example (still using "lambda" syntax here to not muddle the issue,
> I'll discuss your alternatives to "lambda" below):
>
> // Task: Select five largest even numbers from the array:
>
> // (0) Theoretically possible with type inference:
> AIntArray.Filter(lambda X div 2 = 0).Sort(lambda X > Y).Take(5);
How is that possible? In "lambda X > Y " how does the compiler know, if 
X or Y is the first param?

>
> // (1) My proposal
> AIntArray.Filter(lambda TIntFilter as X div 2 = 0).Sort(lambda TIntCmp
> as X > Y).Take(5);
And that is a good example *against* anonymous functions. Even with some 
c# background (and it does remind me of it / maybe general dotNet), I 
had to read it several times.
Sure, if it was highlighted it might be easier to find the keywords 
lambda/as and to know where the expression (the truncated "result :=" 
statement starts.


> // (2) Without "as"
> AIntArray.
>    Filter(lambda TIntFilter; begin Result := X div 2 = 0 end).
>    Sort(lambda TIntCmpl; begin Result := X > Y; end).Take(5);

You comparison is tainted. the begin/end are not needed. Though, I 
actually would like them required. Well at least the end. The lambda 
might serve as the opening.

AIntArray.
   Filter(lambda TIntFilter; Result := X div 2 = 0 end).
   Sort(lambda TIntCmpl; Result := X > Y; end).Take(5);

And that is of course because of your preference for keyword over typecast. Though you are right, even in a typecast a keyword would be good to indicate this code is not executed right away.

   AIntArray.
   Filter(TIntFilter(lambda Result := X div 2 = 0 end).
   Sort(TIntCmpl(lambda Result := X > Y end).Take(5);

Then a none type casted lambda could return a "procedure();", no params, no result.

> // (4) Without anonymous functions:
> function IsEven(X: Integer): Boolean; begin
>    Result := X div 2 = 0;
> end;
> function IsGreaterThan(X, Y: Integer): Boolean; begin
>    Result := X > Y;
> end;
> // ... possibly a lot of code here
> AIntArray.Filter(@IsEven).Sort(@IsGreaterThan).Take(5);
And the actual fitter/sort line is so much easier to read. Really, so 
much easier...

> As you can see, there is a spectrum of expressive power vs language simplicity.
> It is debatable at which position of the spectrum Pascal should be,
> but my opinion is that (4) is way too weak, (0) is probably too strong,
> and (1) is easier to read then (2), (3) or (4) for any reasonably
> literate programmer,
actually from a point of readability
      TIntCmpl(lambda Result := X > Y end
looks easiest to me. WIthin the typecast, you have only an opening 
/closing keyword. The rest is the code. No distraction




>> We could also use the new, have a constructor for everything (TArray.Create)
>> style. Personally, the idea appals me, but
>>     TVisitor.Create(Result := x + 5)
> I actually dislike this syntax even for arrays.
As I said: the idea appals me

>> Another way to avoid the "as"
>>    lambda(TVisitor) .... end
>> lambda acts as "begin" to the block, so there always must be an end.
> Why not also omit "end" then? Just say that "lambda" must be followed
> by a single statement,
No Pascal is verbose. It must be a proper block. TO easy to misread 
otherwise.
  It does not have to finish with end, there could be another keyword. 
(Like in repeat until pair).

If there is no block
   Foo(lambda TFunc x = a, lambda TFunc y<b)
versus
   Foo(lambda TFunc x = a(lambda TFunc y<b))

And if (another of those I personally do not like it) tuples will come, 
then
Foo(lambda TFunc x = (a, lambda TFunc y<b))
where x is a tuple, and the bracket is too.

I want a none return ticket to a different planet.

> then for the case of many statements, "begin..end" should be used like
> in normal blocks.
> The only problem is with local declarations, but I guess it is
> possible to disambiguate
> based on "var", "const" and "type" keywords appearing after "lambda".
Argh yes, I hadn't thougt of that yet.

Well then that just makes it an even bigger monstrosity.
I am not going to think about that now. To much work for something that 
I do not want in first....

>
>> See above. The omission "of Result :=" is IMHO not desirable.
> Are you sure? Note that *any* useful single-statement function will
> start exactly like this
> (strictly speaking, it could be also be call to "exit", but obviously
> it makes no difference).
> And single-statement functions are the most important use case for
> anonymous functions --
> basically, if it takes several lines of code anyway, then in might as
> well be a named function.

Yes. I used them plenty in perl. But this is pascal. Not perl.

>> IMHO the existing procedure/function keywords should be kept. But with the requirement of using a defined type
>> Foo(  function as TVisitor; Result := x+5 end; );
>> Foo(  function as TVisitor; begin Result := x+5 end; );
>> Foo(  function of TVisitor; begin Result := x+5 end; );
>> Foo(  function TVisitor( Result := x+5 )    );
> Yes, this could work too, and it does extend well to named functions/procedures:
>
> procedure TForm1.Grid1OnDrawCell as TGridOnDrawCell;
we need to find a better substitute for "as"
using, like, of,

procedure TForm1.Grid1OnDrawCell prototype(TGridOnDrawCell); // brackets are optional, but seem better





More information about the fpc-devel mailing list