Version 1.11 of ai12s/ai12-0190-1.txt

Unformatted version of ai12s/ai12-0190-1.txt version 1.11
Other versions for file ai12s/ai12-0190-1.txt

!standard 4.4(7/3)          18-12-18 AI12-0190-1/07
!standard 4.5.9(0)
!class Amendment 16-06-02
!status Amendment 1-2012 18-12-10
!status work item 18-12-13
!status ARG Approved 9-0-2 18-12-10
!status work item 16-06-02
!status received 16-05-06
!priority Low
!difficulty Medium
!subject Anonymous functions
!summary
Provide an ability to construct a local anonymous function at the point of a call on a subprogram that has an anonymous access-to-function parameter, or in an instantiation with a formal subprogram parameter.
!problem
We added anonymous access-to-subprogram parameters in Ada 2005 to allow locally-declared subprograms to be passed to other programs which might iterate over some data structure, applying the passed subprogram multiple times, perhaps as part of a search, or an update, or a transformation of some sort. Being able to pass local subprograms to other subprograms is a fundamental part of "functional" programming, but also appears in other programming paradigms, including old fashioned numeric integration packages, etc.
To enhance the utility of this feature, it is convenient if the subprogram being passed can be constructed at the point of call, rather than requiring a separate declaration. AI12-0189 addresses the case where a procedure (as opposed to a function) is to be passed as the actual parameter. We would like to provide something similar for passing a locally-constructed function as a parameter.
!proposal
An anonymous_function can be used in a context where the expected type is a single anonymous access-to-function type, or as the actual parameter for a formal function. It is roughly equivalent to using the name'Access (or simply name) of an expression function which is declared at the point of use, with parameter types, modes, etc. taken from that of the expected access-to-function type (or the formal function). Only the formal parameter names come from the anonymous_function.
primary ::= anonymous_function
anonymous_function ::= ( function [ function_formal_parameter_list ] return expression )
function_formal_parameter_list ::= ( identifier { , identifier } ) | formal_part
We allow only a single expression as the body of the anonymous_function. Given that we now have "if" expressions and "case" expressions, this is not a serious limitation. The proposed addition of "declare expressions" provides even more flexibility if needed.
!wording
Replace 4.4(7/3) with:
primary ::= numeric_literal | null | string_literal | aggregate | name | allocator | (expression) | (conditional_expression) | (quantified_expression) | anonymous_function
Add section after 4.5.8:
4.5.9 Anonymous Functions
Anonymous functions provide a way to define a function at a point where an access-to-function type is the expected type, or where there is an expected function profile determined by a generic formal subprogram parameter.
Syntax
anonymous_function ::= (function [function_formal_parameter_list] return expression)
function_formal_parameter_list ::= formal_part | (identifier {, identifier})
Name Resolution Rules
In a context where there is an expected type rather than an expected profile for an anonymous_function, the expected type shall be a single anonymous access-to-function type, and the profile of this type is considered the expected profile for the anonymous_function. The result type of the expected profile of the anonymous_function is the expected type for the expression of the anonymous_function. If there is no function_formal_parameter_list, the expected profile shall have no parameters. If the function_formal_parameter_list is a formal_part, then it shall be subtype conformant to the expected profile if there is an expected type, or merely mode conformant otherwise. If the function_formal_parameter_list is a sequence of identifiers, the number of identifiers in the sequence shall be the same as the number of formal parameters in the expected profile.
Legality Rules
When used in a context where there is an expected type, the anonymous_function shall be an actual parameter in a call, or a parameter default for a callable entity. When used in a context where there is only an expected profile, the anonymous_function shall be a generic actual parameter in a generic_instantiation for a formal subprogram parameter, or as the subprogram_default for such a formal subprogram parameter.
Static Semantics
An anonymous_function used in a context where there is an expected type is equivalent to an expression_function_declaration (see 6.8) declared within the innermost declarative region, with the anonymous_function replaced by an Access attribute_reference of this locally defined function; otherwise, the anonymous_function is equivalent to such a local declaration with the anonymous_function replaced by a name denoting this locally defined function. The profile of this locally defined function has a result type determined by the expected profile, and a formal part determined by the formal_part, if provided in the anonymous_function, or by the formal part of the expected profile otherwise, but with the name of each formal parameter of the expected profile replaced by the corresponding identifier in the sequence of identifiers. The expression of this locally defined expression function is that of the anonymous_function.
AARM To Be Honest: Depending on the nature of the innermost enclosing declarative region, this equivalence might violate the normal syntax rules which would not permit such an expression_function_declaration in such a region.
!discussion
We are using the reserved words FUNCTION and RETURN rather than defining a new reserved word such as LAMBDA. We put them surrounding the (optional) parameter list, as that is their normal place in the syntax for declaring a named function. We use RETURN rather than IS because we believe the RETURN helps indicate that the expression takes the place of the result type, taking advantage of the result type being provided from context.
We considered other names such as "lambda expressions," "function literals," and "function expressions." We ultimately went with "anonymous functions" to avoid confusion between "expression functions" and "function expressions."
We allow, but do not require, a full formal part as part of the anonymous_function. Requiring a full formal part seems unnecessary and verbose, since the parameter (and result) types are always provided by the expected profile determined by the formal parameter.
We are only supporting defining anonymous functions using this proposed "anonymous_function" construct. Anonymous procedures are nicely handled with the loop-body proposal (AI12-0189). In any case, mixing statements inside expressions seems like a bad idea.
One place where it might be nice to allow "anonymous procedures" would be when you want to pass in a do-nothing procedure, which is not uncommon when instantiating a generic with a formal procedure. We allow using "null" as the default for a formal procedure, as well as when defining a null procedure. It would seem pretty reasonable to allow "null" as the actual parameter for a formal procedure, meaning a "do-nothing" procedure. We leave that to some other AI, if there is interest in that possibility.
We limit this to cases of anonymous access-to-function types used for formal parameters to callable entities. Other cases, like access discriminants and stand-alone access objects seem like more trouble that they are worth given the potential accessibility level issues, and furthermore those constructs generally occur in contexts where declaring a local subprogram is not a burden.
Similarly we limit uses with only an expected profile to generic actuals and defaults. Function renames and function-valued aspects also provide an expected profile, but could represent an implementation burden without clear value. A later revision could choose to relax some of these limitations.
!example
-- Procedure for plotting a function procedure Plot_Graph
(Fun : access function (X : Float) return Float;
Start, Stop : Float);
...
-- Plot a graph of X-squared from 1 to 20 Plot_Graph (Fun => (function (Z) return Z**2),
Start => 1.0, Stop => 20.0);
-- Function for accumulating some statistic over some subset -- of the records of a database function Database_Query (DB : Database_Handle;
select : access function (Rec : DB_Rec_Type) return Boolean; Combine : access function (Accum : Float; Rec : DB_Rec_Type) return Float);
... -- Compute the sum of squares of the records with a large Value field. Large_Val_Sum_Of_Squares := Database_Query
(My_Database,
select => (function (Rec) return (Rec.Value >= N), Combine => (function (Accum, Rec) return Accum + Rec.Value ** 2));
!comment The following were for the version approved and then recended in
!comment December 2018, except to replace "function_expression" with
!comment "anonymous_function" globally.
!corrigendum 4.4(7/3)
Replace the paragraph:
primary ::= numeric_literal | null | string_literal | aggregate | name | allocator | (expression) | (conditional_expression) | (quantified_expression)
by:
primary ::= numeric_literal | null | string_literal | aggregate | name | allocator | (expression) | (conditional_expression) | (quantified_expression) | anonymous_function
!corrigendum 4.5.9(0)
Insert new clause:
Anonymous functions provide a way to define a function at a point where an access-to-function type is the expected type, or in a generic instantiation as an actual parameter corresponding to a formal subprogram parameter.
Syntax
anonymous_function ::= (function [function_formal_parameter_list] return expression)
function_formal_parameter_list ::= formal_part | (identifier {, identifier})
Name Resolution Rules
In a context where there is an expected type rather than an expected profile for a anonymous_function, the expected type shall be a single access-to-function type, and the profile of this type is considered the expected profile for the anonymous_function. The result type of the expected profile of the anonymous_function is the expected type for the expression of the anonymous_function. If there is no function_formal_parameter_list, the expected profile shall have no parameters. If the function_formal_parameter_list is a formal_part, then it shall be subtype conformant to the expected profile if there is an expected type, or merely mode conformant otherwise. If the function_formal_parameter_list is a sequence of identifiers, the number of identifiers in the sequence shall be the same as the number of formal parameters in the expected profile.
Static Semantics
A anonymous_function used in a context where there is an expected type is equivalent to a local expression_function_declaration (see 6.8), with the anonymous_function replaced by an Access attribute_reference of this locally defined function; otherwise, the anonymous_function is equivalent to such a local declaration with the anonymous_function replaced by a name denoting this locally defined function. The profile of this locally defined function has a result type determined by the expected profile, and a formal part determined by the formal_part, if provided in the anonymous_function, or by the formal part of the expected profile otherwise, but with the name of each formal parameter of the expected profile replaced by the corresponding identifier in the sequence of identifiers. The expression of this locally defined expression function is that of the anonymous_function.
!ASIS
** TBD.
!ACATS test
An ACATS C-Test is needed to check that the new capabilities are supported.
!appendix

From: Tucker Taft
Sent: Friday, May 6, 2016  2:05 PM

Now that we have a number of language-defined subprograms that take
access-to-subprogram parameters, it seems worth considering supporting some kind
of "anonymous" function/procedures.  Here are two proposals, one for anonymous
(lambda) functions, and one for anonymous (loop-body) procedures:

[Editor's note: See AI12-0189-1 for the other proposal.]

Lambda functions:

A lambda_function can be used in a context where the expected type is a single
access-to-function type (or as the actual parameter for a formal function).  It
is roughly equivalent to using the name'Access (or simply name) of an expression
function which is declared at the point of use, with parameter types, modes,
etc. taken from that of the expected access-to-function type (or the formal
function).  Only the formal parameter names come from the lambda function.

    primary ::= lambda_function

    lambda_function ::= ( LAMBDA [ lambda_parameter_list ] expression )

    lambda_parameter_list ::= ( identifier { , identifier } )

Here is an example:

    --  Replace control chars with '?'
    Ada.Strings.Fixed.Translate
      (Str, (lambda (C) (if C < ' ' then '?' else C)));

    --  Procedure for plotting a function
    procedure Plot_Graph
      (Fun : access function (X : Float) return Float;
       Start, Stop : Float);

    ...

    --  Plot a graph of X-squared from 1 to 20
    Plot_Graph (Fun => (lambda (Z) Z**2), Start => 1.0, Stop => 20.0);

=====================

Again, if there is interest, I can write up these ideas as AIs.  As mentioned,
we discussed the loop-body procedures a bit in Vermont.

****************************************************************

From: Brad Moore
Sent: Saturday, May 7, 2016  8:40 AM

I'm definitely interested in seeing some improvements in this area, but I'd like
to see a single, more general solution that covers both these cases (expression
functions and iterators) as well as other cases. Essentially, I'd like to be
able to provide an anonymous subprogram for any parameter of an
access-to-subprogram type (not just expression functions), and possibly other
places such as generic formal subprograms.

This capability already exists in C++, C#, and Java in some form.

The idea here is to write the full body of the subprogram inline, including the
parameter profile, but omitting the name for the subprogram.

Tuckers examples might look like;

-- Example using an expression function
Ada.Strings.Fixed.Translate
   (Source => Str,
    Mapping => (C : Character) is (if C < ' ' then '?' else C));

--  Procedure for plotting a function
procedure Plot_Graph
   (Fun : access function (X : Float) return Float;
    Start, Stop : Float);

    ...

--  Another expression function
--  Plot a graph of X-squared from 1 to 20 Plot_Graph (Fun => (Z : Float) is (Z**2)),
             Start => 1.0, Stop => 20.0);


-- Example using a procedure.
-- Iterating via Ada.Environment_Variables Ada.Environment_Variables.Iterate
    (Process => (Name, Value : String) is
     begin
        Put_Line (Name & " => " & Val);
     end);

-- Another example showing not just for iteration and expression
-- functions

-- procedure for executing N Blocks in parallel procedure Parallel_Blocks
   (Number_Of_Blocks : Positive;
    Process : not null access procedure (Worker : Positive));

-- Call to execute two procedures in parallel using inline procedure
-- featuring a declaration
Parallel_Blocks (Number_Of_Blocks => 2,
                  Process => (Worker : Positive) is
    declare
       X : Integer := Foo;
    begin
       if Worker = 1 then
         Do_Lengthy_Processing_A (X);
       else
         Do_Other_Processing (X);
       end if;
    end);

****************************************************************

From: Tucker Taft
Sent: Saturday, May 7, 2016  2:17 PM

> The idea here is to write the full body of the subprogram inline,
> including the parameter profile, but omitting the name for the subprogram. ...

I believe readability goes down if you start embedding statements inside
expressions. Since you can always declare a local subprogram, trying to bury a
sequence of statements inside an expression is unnecessary, and doesn't really
improve "writability" much either.

Also, it is always redundant to specify the parameter types for a lambda
function, given that they would only be allowed in contexts where the expected
profile is known.

****************************************************************

From: Jean-Pierre Rosen
Sent: Saturday, May 7, 2016  2:29 PM

But this kind of redundancy appears often in Ada, on the ground that the reader
should not have to wander to far-away places to get important information like
types.

****************************************************************

From: Tucker Taft
Sent: Saturday, May 7, 2016  2:41 PM

Well, I suppose it would be easy enough to allow a full formal parameter part in
the "lambda" function syntax, as in the proposed syntax for the loop-body
procedure.  But I certainly wouldn't want to require it.

****************************************************************

From: John Barnes
Sent: Sunday, May 8, 2016  4:15 AM

I am always wary of mixing expressions and statements. I went to a lecture on
lambda expessions by Peter Landin at a Summer School in Oxford in 1963. I must
read the notes.

I am in favour provided it deosn't cause confusion and/or make the next version
of my book much bigger.

****************************************************************

From: Erhard Ploedereder
Sent: Monday, May 9, 2016  9:18 AM

> Also, it is always redundant to specify the parameter types for a
> lambda function, given that they would only be allowed in contexts
> where the expected profile is known.

But this would mean that lambdas cannot take lambdas as arguments, would it not?
(Which would really turn off the functional crowd).

****************************************************************

From: Tucker Taft
Sent: Monday, May 9, 2016  10:27 AM

I don't follow this.  If the profile of the lambda is known, then so is the
profile of any arguments of the lambda that are themselves access-to-functions,
so nesting should be no problem.  If you can show an example, I can verify this
claim, but I will admit I am not up to producing a realistic example where a
lambda takes a lambda.

****************************************************************

From: Edmond Schonberg
Sent: Monday, May 9, 2016  10:42 AM

If nothing else, how do you disambiguate  F (X) within the expression if F is a
lambda parameter?  An array of Xs, a a type with implicit dereference, or a
call?

****************************************************************

From: Tucker Taft
Sent: Monday, May 9, 2016  10:52 PM

You know the (access-to-function) type of F by context.

****************************************************************

From: Jeff Cousins
Sent: Tuesday, May 10, 2016  4:04 AM

Lambda functions seem to me a bit like a WIBNI (wouldn't it be nice if) that, if
we have at all, should be tucked away in some optional annex. Would lambda be a
new reserved word?

****************************************************************

From: Tucker Taft
Sent: Thursday, May 12, 2016  7:48 PM

Yes, I would recommend a new reserved word, as just trying to do lambda
functions with clever syntax would be harder to read, in my view.  In my view
the loop-body procedures are more important than lambda functions, but others at
AdaCore feel that lambdas are critically important.  But Randy reminded me that
Bob Duff has at least something like this on his plate, so I'll let him take a
stab at it first if he so desires.

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 12, 2016  5:21 PM

> Again, if there is interest, I can write up these ideas as AIs.  As
> mentioned, we discussed the loop-body procedures a bit in Vermont.

Right, and this topic was assigned to Bob Duff (certainly the second idea, and
arguably the first as well). Given your well-known huge pile of homework, I
recommend that you let Bob write the AI(s) on this topic. (If he doesn't do it,
we can revisit, there certainly isn't any rush at this point.)

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, May 12, 2016  6:30 PM

You are right. If the context of lambda construction always provides a specified
access-to-function type (obviously including its parameters), calling lambdas
with lambdas as arguments is not a problem.

The problem appears when lambdas can be named and lead an independent existence,
as in
   inc = lambda(x) (x + 1);
   conc = lambda(x) (x & "abc");
   twice = lambda(f, x) (f(f(x));
Now, we know nothing about the type of f (short of doing a very general type
inference) but we can say twice(inc, 5), while twice(conc, 5) should be illegal,
but how to tell without said type inference?

But you are not proposing named lambdas, so all is fine.

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 12, 2016  6:51 PM

> But you are not proposing named lambdas, so all is fine.

Sorry to toss out a bit of ignorance here, but what is the point of a "named
lambda"? Isn't that the same silliness as a "named anonymous access type"
(something we rightfully decided was too silly to pursue)?

It seems to me that a "named lambda" is essentially the same thing as a normal
subprogram. In your above example, the parameters are typeless, but if that's
allowed at all, it should be allowed everywhere (thus there is no difference
between a "named lambda" and any other kind of named subprogram).

If we were to do a more general lambda facility (which I've against for
readability reasons, but that's not relevant to this discussion), then surely
the context would have to identify an access-to-subprogram type (nothing being
typeless in Ada). The above sort of thing would be possible:

    Inc : constant access function (X : Integer) return Integer := (lambda(X) X + 1);
    Conc : constant access function (X : String) return String := (lambda(X) X & "abc");

And this would essentially be a "named lambda". And not appreciably different
than:

    function Inc (X : Integer) return Integer is (X + 1);
    function Conc (X : String) return String is (X & "abc");

(Which I hope most programmers would prefer.)

So the operative thing in your example that causes trouble is typeless-ness, not
whether or not the lambda is named in some sense. But Tucker (nor Brad for that
matter) were proposing any sort of typeless-ness. So I don't think there is any
problem.

****************************************************************

From: Brad Moore
Sent: Thursday, May 12, 2016  7:56 PM

> Sorry to toss out a bit of ignorance here, but what is the point of a
> "named lambda"? Isn't that the same silliness as a "named anonymous access type"
> (something we rightfully decided was too silly to pursue)?

I haven't the definitive answer to this question, but I think I have a good
guess.

In such languages as C++ and Java, lambdas provide another missing capability.
They provide a means to essentially write a nested subprogram, which is
important because such subprograms can access variables in the enclosing scope.

Ada doesn't need that capability, because it has had it from day one, in Ada 83
with nested subprograms.

I see a named lambda being particularly useful in C++ because it might be needed
more than once, possibly passed as parameters into 2 or more separate function
calls. Rather than write the same lambda function multiple times, the named
lambda allows C++ programmers to write the function once, and then pass that
lambda into the separate call sites.

Ada doesn't seem to need that capability, because one can just write a nested
subprogram and pass that in, instead of using a lambda.

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 12, 2016  8:12 PM

On top of which, one can "name" a lambda as I showed (using an object with an
anonymous-access-to-subprogram). So if you really need two copies of a lambda,
that's a way to do it. (But just using a subprogram makes more sense anyway.)

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 12, 2016  9:20 PM

[Editor's note: From another thread, see AI12-0188-1.]

...
> I agree that some more discussion is needed.

Surely. I have to wonder why "others at AdaCore feel that lambdas are
critically important". Why is it so hard to stick an expression function in a
declare block? That's 20 extra characters or so?? It seems I'm missing
something (or perhaps that lambda proponents are, because none of the proposals
are going to weaken typing).

****************************************************************

From: Erhard Ploedereder
Sent: Saturday, May 14, 2016  2:30 PM

> Sorry to toss out a bit of ignorance here, but what is the point of a
> "named lambda"?

It is the corner stone of functional programming in all the functional
languages. So people coming from a functional background are looking for that.

It is not quite a named subprogram. It is subclass, namely a named expression
function.

I agree with the remainder of what you wrote.

****************************************************************

From: Brad Moore
Sent: Thursday, May 12, 2016  8:19 PM

>> ... I'm really dubious that a separate feature is warranted for this.
>
> I think you are in the minority on this one.

Just for comparison, two new syntax variants with specific usage for iterating
through map-like containers ...

    for (Key => Elem) of Container loop
       ...
    end loop;

and

   for (Key => <>) of Container loop
      ...
   end loop;

vs a single syntax capability that is much more general purpose including
other usages that have been discussed in the lambda thread...

    Container.Iterate (Key is
       begin
          ...
       end);

    Container.Iterate((Key, Element) is
       begin
          ...
       end);

Both proposals seem relatively similar in terms of ease of expression.

With specific syntax, there is a danger that more people will not know of its
existence, or remember its existence when a possibility for usage arises. With
a more general solution, chances are more people will think of using the
capability.

So far, I am agreeing with Randy here. I think most people are interested in a
solution, but not necessarily settled on the proposed solution.

   But in any case it sounds
> like we should discuss the various alternatives in an ARG meeting
> before I spend time writing it up, given the amount of other homework
> still on my plate...

I agree that some more discussion is needed.

****************************************************************

From: Randy Brukardt
Sent: Thursday, May 12, 2016  9:20 PM

> Both proposals seem relatively similar in terms of ease of expression.

Well, I was replying to Tucker's "loop procedure" proposal, which looks like a
loop. (I don't think anyone other than yourself is interested in your general
proposal). Tucker's suggestion (based on his original message and an
appropriate Iterate) would look like:

    for (Key, Element) of Container.Iterate(<>) loop
       ...
    end loop;

which is so close to his first case that it would be madness to provide both.
[And the <> is optional above.]

And it is easy to imagine extending his original idea to allow using <> in
place of parameters not wanted (they'd still exist, but be anonymous), thus
getting:

    for (Key, <>) of Container.Iterate loop
       ...
    end loop;

which handles the second case perfectly.

> With specific syntax, there is a danger that more people will not know
> of its existence, or remember its existence when a possibility for
> usage arises. With a more general solution, chances are more people
> will think of using the capability.

Or even more likely never even consider it because they can't grok lambdas.

I'm in favor of Tucker's loop syntax as given above (it's natural and could be
used for all of the containers). Indeed, it's a better idea than the existing
cursor iterators, which we may not have defined at all if we had the above.

I'm pretty much against all of the other proposals, I don't see the value of
the complications (especially as access-to-anything ought to be minimized,
especially in reusable code). And the idea of sticking statements in the
middle of expressions is a bridge too far to me. All of the languages that you
listed as having lambdas seem to me to be also those languages that are
actively against readability!

I'm also getting worried about feature creep. We expanded expressions to
include if and case and quantified and expression functions because of the
needs of contract aspects. I don't know what is supposed to be driving
lambdas.

...
> I agree that some more discussion is needed.

Surely. I have to wonder why "others at AdaCore feel that lambdas are
critically important". Why is it so hard to stick an expression function in a
declare block? That's 20 extra characters or so?? It seems I'm missing
something (or perhaps that lambda proponents are, because none of the proposals
are going to weaken typing).

****************************************************************

From: Brad Moore
Sent: Thursday, May 12, 2016  10:55 PM

Anonymous functions are fairly common in programming languages, and apparently
can be found in languages including C++, C#, Dart, Erlang, Go, Haskell, Java,
Javascript, List, Lua, Mathematica, Perl, PHP, Python, Ruby, Scala, Smalltalk,
Swift, ...

https://en.wikipedia.org/wiki/Anonymous_function

There must be at least some folks out there who grok lambdas.

Well, I have one more example, that is kind of interesting that I plan to use
for a tutorial at Ada Europe... Interesting here not from the standpoint of
parallelism, but from the standpoint of being called from multiple languages,
and involving multiple anonymous subprogram parameters.

The following non-generic Ada subprogram that can be called from multiple
languages including C, C++, C#, and Java, as it exports the C calling convention
for the C and C++ case, and can be easily ported to C# and Java as well, which I
have done using the GNAT dot net and java compilers....

procedure Parallel_Loop
   (From           : Loop_Index;
    To             : Loop_Index;
    Reset          : not null access procedure;
    Loop_Body      : not null access
      procedure (Start, Finish : Loop_Index);
    Reduce         : not null access procedure);

Basically,
    Reset is used to reinitialize task local variables,
    Loop_Body does the processing of the loop,
    and Reduce combines results produced by the Loop_Body.

Currently to call this routine from Ada to calculate the sum of numbers from 1
to 1_000_000, one might write in Ada....

    package Partial_Sums is new
       Ada.Task_Attributes (Attribute     => Integer,
                            Initial_Value => 0);
    procedure Reset is
    begin
       Partial_Sums.Set_Value (0);
    end Reset;

    procedure Compute_Sum
      (Start, Finish : Parallel.Loop_Index)
    is
       Partial_Sum : Integer renames Partial_Sums.Reference.all;
    begin
       for I in Start .. Finish loop
          Partial_Sum := Partial_Sum + I;
       end loop;
    end Compute_Sum;

    Sum : Integer := 0;

    procedure Reduce () is
    begin
       Sum := Sum + Partial_Sums.Value;
    end Reduce;

    Reducing_Loops.Work_Seeking.Parallel_Loop
      (From           => 1,
       To             => 1_000_000,
       Reset          => Reset'Access,
       Process        => Compute_Sum'Access,
       Reduce         => Reduce'Access);

To call this same Ada library from C#, one can currently write...

    [ThreadStatic]
    private static int partial_sum;
    ...
       int sum = 0;

       paraffin_pkg.parallel_loop
          (from   : 1,
           to     : 1000000,
           reset  : () => { partial_sum = 0; },
           process: (start, finish) =>
             {
               for (int i = start; i <= finish; i++)
                  partial_sum += i;
             },
           Reduce : () => { sum += partial_sum; });

Which of these two versions do you find more readable?

I prefer the C# version mostly because there is less "noise" text, and the
formal parameters of the call are directly associated with the code. In Ada, you
are first presented with a bunch of routines, not knowing their purpose, until
you get down to the call, but then your eyes have to jump up and down to
associate the logic with the call site.

In this example, it appears to be actually easier to call Ada code from C#, than
from Ada, I would say.

If instead, some sort of general lambda feature existed in Ada, I might be able
to write something like...

package Partial_Sums is new
       Ada.Task_Attributes (Attribute     => Integer,
                            Initial_Value => 0);
    Sum : Integer := 0;

    Reducing_Loops.Work_Seeking.Parallel_Loop
      (From     => 1,
       To       => 1_000_000,
       Reset    => is Partial_Sums.Set_Value (0),
       Process  => (Start, Finish) is
          Partial_Sum : constant access Integer :=
             Partial_Sums.Reference;
         begin
            for I in Start .. Finish loop
               Partial_Sum.all := Partial_Sum.all + I;
            end loop;
         end,
       Reduce   => is Sum := Sum + Partial_Sums.Value);

Which I find more readable, but maybe thats just me...

>
> I'm also getting worried about feature creep. We expanded expressions
> to include if and case and quantified and expression functions because
> of the needs of contract aspects. I don't know what is supposed to be
> driving lambdas.

I suppose its mostly just syntactic sugar to hopefully improve readability with
a short hand form of expression, in the same way that loop iterators of Ada 2012
did that for loops.

Also I think it would be beneficial to be able to say that Ada provides a lambda
feature comparable to most other main stream languages.

If I am alone in seeing the benefit of this, then I wont bother promoting the
idea, but then I tend to agree with the worry of feature creep for special
purpose syntax that has limited use. My concern would be to wonder if the same
capability can be provided reasonably with just a library addition.

****************************************************************

From: Randy Brukardt
Sent: Friday, May 13, 2016  12:04 AM

A couple of thoughts rather than a complete response to your message because its
important to hear more from the rest of the group before beating to death ideas
that may not have much support anyway:

...
>> I'm pretty much against all of the other proposals, I don't see the
>> value of the complications (especially as access-to-anything ought to
>> be minimized, especially in reusable code). And the idea of sticking
>> statements in the middle of expressions is a bridge too far to me.
>> All of the languages that you listed as having lambdas seem to me to
>> be also those languages that are actively against readability!

>Anonymous functions are fairly common in programming languages, and apparently
>can be found in languages including C++, C#, Dart, Erlang, Go, Haskell, Java,
>Javascript, List, Lua, Mathematica, Perl, PHP, Python, Ruby, Scala, Smalltalk,
>Swift, ...
>
>https://en.wikipedia.org/wiki/Anonymous_function

We've come to regret almost everything anonymous that has ever been in or added
to Ada. They tend to cause all kinds of definitional and usage problems. I'm
quite opposed to repeating that mistake; every time we've been told how it will
all work out fine, and it never does.

What does help is to have short-hand syntax (like generalized references and
generalized indexing) where named stuff can be used with a shorthand.

Besides, what is really going on in most of those languages is some sort of
poor-man's subprogram type and values. The benefit isn't in anonymity but rather
in having subprogram values. We'd be better off looking in that direction if we
really needed it (but still, all of the subprogram types and values should have
names).

...
> The following non-generic Ada subprogram that can be called from
> multiple languages including C, C++, C#, and Java, as it exports the C
> calling convention for the C and C++ case, and can be easily ported to
> C# and Java as well, which I have done using the GNAT dot net and java
> compilers....
>
> procedure Parallel_Loop
>    (From           : Loop_Index;
>     To             : Loop_Index;
>     Reset          : not null access procedure;
>     Loop_Body      : not null access
>       procedure (Start, Finish : Loop_Index);
>     Reduce         : not null access procedure);
>
> Basically,
>     Reset is used to reinitialize task local variables,
>     Loop_Body does the processing of the loop,
>     and Reduce combines results produced by the Loop_Body.
>
> Currently to call this routine from Ada to calculate the sum of
> numbers from 1 to 1_000_000, one might write in Ada....
>
>     package Partial_Sums is new
>        Ada.Task_Attributes (Attribute     => Integer,
>                             Initial_Value => 0);
>     procedure Reset is
>     begin
>        Partial_Sums.Set_Value (0);
>     end Reset;
>
>     procedure Compute_Sum
>       (Start, Finish : Parallel.Loop_Index)
>     is
>        Partial_Sum : Integer renames Partial_Sums.Reference.all;
>     begin
>        for I in Start .. Finish loop
>           Partial_Sum := Partial_Sum + I;
>        end loop;
>     end Compute_Sum;
>
>     Sum : Integer := 0;
>
>     procedure Reduce () is
>     begin
>        Sum := Sum + Partial_Sums.Value;
>     end Reduce;
>
>     Reducing_Loops.Work_Seeking.Parallel_Loop
>       (From           => 1,
>        To             => 1_000_000,
>        Reset          => Reset'Access,
>        Process        => Compute_Sum'Access,
>        Reduce         => Reduce'Access);
>
> To call this same Ada library from C#, one can currently write...
>
>     [ThreadStatic]
>     private static int partial_sum;
>     ...
>        int sum = 0;
>
>        paraffin_pkg.parallel_loop
>           (from   : 1,
>            to     : 1000000,
>            reset  : () => { partial_sum = 0; },
>            process: (start, finish) =>
>              {
>                for (int i = start; i <= finish; i++)
>                   partial_sum += i;
>              },
>            Reduce : () => { sum += partial_sum; });
>
> Which of these two versions do you find more readable?

Neither. A loop should look like a loop; otherwise causal reading/tools will not
discover where the majority of the work is happening.

Tucker's "loop procedure" proposal does look like a loop; it would make this
look something like:

   for (First, Last) of Reducing_Loops.Work_Seeking.Parallel_Loop
       (From           => 1,
        To             => 1_000_000,
        Reset          => Reset'Access,
        Process        => <>,
        Reduce         => Reduce'Access) loop
      declare
        Partial_Sum : Integer renames Partial_Sums.Reference.all;
      begin
        for I in Start .. Finish loop
           Partial_Sum := Partial_Sum + I;
        end loop;
      end;
   end loop;

...and the rename inside the loop body makes it messier. (You still have the
instance and other subprograms, which to me demonstrate that the original
routine is too complex to be used; I'd never bother trying to understand a
routine that takes THREE subprograms. At least the intent is that parallel loops
are directly supported by Ada syntax and the compiler - no subprograms -
anonymous or otherwise - anywhere.)

****************************************************************

From: Brad Moore
Sent: Friday, May 13, 2016  12:32 AM

...
> Tucker's "loop procedure" proposal does look like a loop; it would
> make this look something like:
>
>     for (First, Last) of Reducing_Loops.Work_Seeking.Parallel_Loop
>         (From           => 1,
>          To             => 1_000_000,
>          Reset          => Reset'Access,
>          Process        => <>,
>          Reduce         => Reduce'Access) loop
>        declare
>          Partial_Sum : Integer renames Partial_Sums.Reference.all;
>        begin
>          for I in Start .. Finish loop
>             Partial_Sum := Partial_Sum + I;
>          end loop;
>        end;
>     end loop;

Ok, I didn't realize Tucker's solution could be applied to this case...
I still worry that people coming from C++, Java, C# etc, might criticize that we
didn't go far enough to allow Reset and Reduce to also be "inlined", or that
other sorts of non-loop cases can't be lambdaized, but I would like to hear
others comments on this as well. John said he had some notes about statements
within expressions from some time ago that would be good to hear.

> ...and the rename inside the loop body makes it messier. (You still
> have the instance and other subprograms, which to me demonstrate that
> the original routine is too complex to be used; I'd never bother
> trying to understand a routine that takes THREE subprograms.

Just thought it would be worth pointing out that C#'s current official
parallelism approach actually looks very similar to the library I have. Their
library also takes three subprograms....

Here is how one would do the same loop using the C# "standard" libraries.

int sum = 0;

Parallel.ForEach
    (source      : Partitioner.Create(1, 1000001),
     LocalInit   : () => 0,        // Reset
     body        : (range, loopState, local) =>
        {
          for (int i = range.Item1; i < range.Item2; i++)
            { local += i; }
          return local;
        },
     localFinally: local =>        // Reduce
        {Interlocked.Add(ref sum, local);});

Its a similar looking library routine, except that it is genericized so that the
thread local variables are passed into the body lambda, instead of having to be
declared separately, and that the programmer has to supply locking around the
code in the Reduce routine.

****************************************************************

From: Jean-Pierre Rosen
Sent: Friday, May 13, 2016  2:23 AM

> I still worry that people coming from C++, Java, C# etc, might
> criticize that we didn't go far enough to allow Reset and Reduce to
> also be "inlined", or that other sorts of non-loop cases can't be
> lambdaized
<rant>
We've been trying for 30 years to find the killer feature that would attract
those people. The truth is that they don't intend to switch to Ada, and that
their criticizing is just for finding excuses for not switching languages. Ada
has its own strengthes, most of which reside in /not/ doing things the same way
as other languages.

So I suggest we just close our ears to these criticisms </rant>

****************************************************************

From: Jeff Cousins
Sent: Friday, May 12, 2016  2:55 AM

...
> We've come to regret almost everything anonymous that has ever been in
> or added to Ada. They tend to cause all kinds of definitional and
> usage problems. I'm quite opposed to repeating that mistake; every
> time we've been told how it will all work out fine, and it never does.

John B certainly regrets most of the anonymous stuff, and purged a lot of it
when he revised his book.

****************************************************************

[Editor's note: This thread continues in AI12-0189-1, since it is turning back
to loops.]

****************************************************************

From: Tucker Taft
Sent: Tuesday, October 4, 2016  11:02 PM

Here is an update. [This is version /02 of the AI - Editor.] I have shifted
the syntax so it doesn't rely on a new reserved word "lambda" any more. Might
want to change the name of the construct as well if we go this direction.
I have provided !problem and !discussion sections.


****************************************************************

From: Gary Dismukes
Sent: Wednesday, October 5, 2016  12:09 PM

I definitely prefer including "function" in the syntax.  I think it makes it
much easier to read, and avoids the unpleasant double-paren at the beginning.

(And thanks for eliminating "lambda"!)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, October 5, 2016  7:58 PM

The alternative with both "function" and "return" looks the best to me. The
others look like something is missing.

****************************************************************

From: Tucker Taft
Sent: Wednesday, October 12, 2016  4:30 PM

Essentially everyone who saw this likes having "function" as part of the syntax.
So here is an update to the update. [This is version /03 of the AI - Editor.]  I
also changed the syntax category to be "function_expression" in analogy with
"if_expression" and "case_expression".

Here is a simple example of the syntax, showing a function_expression that
returns the square of its operand.

    (function (X) return (X**2))

Types of parameter(s) and result come from the expected profile.

****************************************************************

From: Raphael Amiard
Sent: Wednesday, October 12, 2016  4:46 PM

I'm confused about something though. I will have to look at the minutes, but
from what I remember from the last meeting, the general agreement was that:

- In most languages lambdas/anonymous functions imply closures
- Making them equivalent to nested functions only gave a negligible boost in
  expressivity and readability.
- But on the other hand would be confusing to people expecting them to work like
  *real* anonymous functions in other languages

So in the end my understanding was that we should investigate the closure
behavior, and that if not it was not deemed a worthy addition to the language.

I don't see any mention of that in the AI, on the contrary it does exactly what
we agreed was not worth it.

Did I miss something ?

****************************************************************

From: Raphael Amiard
Sent: Wednesday, October 12, 2016  4:49 PM

I did not miss something. Here is the relevant extract:


Erhard says that a simple version isn't interesting. People he knows are only
interested in being able to return constructed lambdas. Steve wonders if
supporting a syntax sugar only version would do more harm than good. People
would think that we are just faking. Erhard thinks we could try to make this
safe by the right restrictions, that would be a boon. (C++ just crashes if one
does.)
Keep alive (original version): 2-4-6.
Keep alive (complex version): 6-1-5. (A complex version would support some sort
of constructed lambda.) Tucker will take another shot at this. Florian would
like to help.

****************************************************************

From: Tucker Taft
Sent: Wednesday, October 12, 2016  5:50 PM

> I did not miss something. Here is the relevant extract:

Good point.  I missed/forgot that.  On the other hand, if we can at least agree
on the syntax, we could then look into the semantics. ;-)

It seems what is being requested is the ability to write something like this:

    function Filter(Pattern : String) return access function (X : String) return Boolean;

This will return a filter which returns True only if X matches the pattern.

Trying to write this:

     function Filter(Pattern : String)
       return access function (X : String) return Boolean is
     begin
         return (function (X) return Match(X, Pattern));
     end Filter;

This is do-able by treating such a result as living on the secondary stack, I
suppose, which we would *not* cut back until the returned function is no longer
being used.

So it seems that the proposed syntax could work, provided we defined the
semantics of returning an access-function as having this possibility of
preserving the context on the secondary stack.

Personally, I am not convinced that this added functionality is that important,
but others seem to think that without it the feature is useless.  If there is
interest, for the next ARG meeting I could add more details about the
implementation requirements associated with this added functionality, presuming
I have captured it correctly.

****************************************************************

From: Steve Baird
Sent: Wednesday, October 12, 2016  6:01 PM

It gets more interesting ("interesting" sounds better than "preposterously
inappropriate for Ada") if the anonymous function can refer to things declared
inside of Filter, so that they have to persist after Filter returns.

Even if these guys are pretty much just syntactic sugar, we need to be a little
bit careful in defining them via an equivalence rule because they can refer to
the implicitly declared object of a quantified_expression or of an
iterated_component_association.

Since that cannot be done with an explicitly declared function, a simple
equivalence rule breaks down in this case.

Consider the following (admittedly contrived) example

    function Foo (Func : access function return Character) return Boolean
      is ... ;

    Flag : Boolean := (for some C in Character =>
                         Foo (Func => (function return (C))));

This is not a fundamental problem - just a case that we would need to confirm is
defined correctly.

[Randy - yes, I mentioned this one to you a while back.]

****************************************************************

From: Tucker Taft
Sent: Wednesday, October 12, 2016  8:07 PM

> ...
> It gets more interesting ("interesting" sounds better than
> "preposterously inappropriate for Ada") if the anonymous function can
> refer to things declared inside of Filter, so that they have to
> persist after Filter returns.

Yes, I was presuming the entire stack frame of Filter would be preserved on the
secondary stack, so you could refer to anything visible at the point of the
function return.  This seems implementable.  You just have to put all things
that are referenced (directly or indirectly) by the return statement on the
secondary stack rather than the primary stack. For simplicity, you could just
allocate everything local to Filter on the secondary stack.

>
> Even if these guys are pretty much just syntactic sugar, we need to be
> a little bit careful in defining them via an equivalence rule because
> they can refer to the implicitly declared object of a
> quantified_expression or of an iterated_component_association.
>
> Since that cannot be done with an explicitly declared function, a
> simple equivalence rule breaks down in this case.
>
> Consider the following (admittedly contrived) example
>
>    function Foo (Func : access function return Character) return Boolean
>      is ... ;
>
>    Flag : Boolean := (for some C in Character =>
>                         Foo (Func => (function return (C))));
>
> This is not a fundamental problem - just a case that we would need to
> confirm is defined correctly.

Agreed.  I don't see any strong reason to define these by an equivalence rule.
I was using the equivalence more to help understand the limitation to a single
expression, which is similar to an expression function.

One twist that I considered for ParaSail was, when the formal was of a
parameterless function type, the caller would be allowed to pass a simple
expression of the return type as the actual parameter (rather than a lambda).
You could then (in ParaSail syntax) define a short-circuit operation like "and
then" as:

    op "and then"(Left : Boolean; Right : func() -> Boolean) -> Boolean is
       if Left then
          return Right();
            //  evaluate the right-hand operand only if necessary
       else
          return #false;
       end if;
    end op "and then";

This doesn't work quite as well when the parameter type is necessarily an
access-to-function type as in Ada, since the actual parameter for Right might be
overloaded so that it could legally be interpreted as either of the correct
access-function type, or of the access-function's result type.  It would be
upward incompatible to consider that ambiguous, though being able to gain the
feature of unevaluated parameters might be worth it!

****************************************************************

From: Steve Baird
Sent: Wednesday, October 12, 2016  10:44 PM

> This seems implementable.

True, but at some cost in complexity.

en.wikipedia.org/wiki/Parent_pointer_tree says:

   The term spaghetti stack is closely associated with implementations
   of programming languages that support continuations. Spaghetti stacks
   are used to implement the actual run-time stack containing variable
   bindings and other environmental features. When continuations must be
   supported, a function's local variables cannot be destroyed when that
   function returns: a saved continuation may later re-enter into that
   function, and will expect not only the variables there to be intact,
   but it will also expect the entire stack to be present so the
   function is able to return again. To resolve this problem, stack
   frames can be dynamically allocated in a spaghetti stack structure,
   and simply left behind to be garbage collected when no continuations
   refer to them any longer. This type of structure also solves both the
   upward and downward funarg problems, so first-class lexical closures
   are readily implemented in that substrate also.

   Examples of languages that use spaghetti stacks are:

     Languages having first-class continuations such as Scheme
        and Standard ML of New Jersey
     Languages where the execution stack can be inspected and
        modified at runtime such as Smalltalk
     Felix
     Cilk

The interactions with tasking, masters, and finalization would also need to be
worked out.

****************************************************************

From: Tucker Taft
Sent: Thursday, October 13, 2016  7:42 AM

>   The term spaghetti stack is closely associated with implementations
>   of programming languages that support continuations. ...

I am not sure we need support for full continuations to support returning
function expressions.  If we allocate everything of interest on the secondary
stack and then return the access-to-function without cutting it back (and
without performing any finalization), what more do we need to do?  I have
presumed the accessibility checks would treat this roughly the same way we treat
access-to-subprogram parameters, as though the accessibility level is deeper
than any master, so you can't convert it to any named access-to-subprogram type.
All you can do is pass the result of a call to an access-to-subprogram
parameter, or return the result of the call.  With these restrictions, you
cannot create arrays of these function expressions, nor store them in any object
of a named access type.

In any case, I agree that none of this is trivial.  Also, looking at other
languages that support lambda expressions, many of them support only passing
them as parameters, so I don't think Ada would be in such a bad situation if we
started out only supporting them as parameters, and consider support for
returning them as a later extension.

****************************************************************

From: Raphael Amiard
Sent: Thursday, October 13, 2016  10:23 AM

> Good point.  I missed/forgot that.  On the other hand, if we can at least
> agree on the syntax, we could then look into the semantics. ;-)

Fine by me ! I guessed that this was an omission :)

> It seems what is being requested is the ability to write something like this:
>
>   function Filter(Pattern : String) return access function (X : String) return Boolean;
>
>This will return a filter which returns True only if X matches the pattern.

This is one of the things that you could do indeed.

>Trying to write this:
>
>    function Filter(Pattern : String)
>      return access function (X : String) return Boolean is
>    begin
>        return (function (X) return Match(X, Pattern));
>    end Filter;

Yeah that's a good example, because we can see that the lambda-function captures
the Pattern parameter.

> This is do-able by treating such a result as living on the secondary stack,
> I suppose, which we would *not* cut back until the returned function is no
> longer being used.
>
> So it seems that the proposed syntax could work,

I like the syntax very much indeed ! This is akin to what Javascript/Lua/ML do.

> provided we defined the semantics of returning an access-function as having
> this possibility of preserving the context on the secondary stack.

This is not sufficient. Suppose you want to then store the resulting filter
lambda function, for example to use in your *lazy* iterator (that could be
implemented using a generator ^^, or not), that will call it everytime the users
calls "Next" on it.

> Personally, I am not convinced that this added functionality is that
> important, but others seem to think that without it the feature is useless.
> If there is interest, for the next ARG meeting I could add more details
> about the implementation requirements associated with this added
> functionality, presuming I have captured it correctly.

Well, I disagree. I think it's important if you want to program in a certain
style. It makes certain patterns much more expressive. One example is the
previous example of providing filters to iterators:

for Node of Tree.Search(function (N): N.Kind = Function_Call) loop
    Do_Stuff;
end loop;

If search is done in such a way that it returns an iterator object (which it
should, because you might want to abort the search before the end), then it will
need to take ownership of the lambda, or store a reference to it (depending on
the semantics of the lambda objects).

Another very common example is giving event handlers in event oriented
programming:

procedure Build_GUI is
    My_Button  : Button;
    My_Form    : Form;
begin
    Initialize_Payment_Form (My_Form);
    Button.Set_On_Click (function (B): My_Form.Show);
end Build_GUI;

Of course, here, to be correct, the Form type needs to be some kind of
ref-counted type. That's fine.

****************************************************************

From: Tucker Taft
Sent: Thursday, October 13, 2016  11:21 AM

> ...
>> So it seems that the proposed syntax could work,
>
> I like the syntax very much indeed ! This is akin to what Javascript/Lua/ML
> do.
>
>> provided we defined the semantics of returning an access-function as
>> having this possibility of preserving the context on the secondary stack.
>
> This is not sufficient. Suppose you want to then store the resulting
> filter lambda function, for example to use in your *lazy* iterator
> (that could be implemented using a generator ^^, or not), that will call it
> everytime the users calls "Next" on it.

I am not convinced we need to store these, so I would have to see the problem we
are trying to solve.  I am sure you could construct an example that could take
advantage of storing them, but I would suspect (hope?) that there are other ways
of accomplishing the same thing without doing so.  I am not a big fan of burying
everything in lambdas (as explained a bit more below).

>> Personally, I am not convinced that this added functionality is that
>> important, but others seem to think that without it the feature is
>> useless.  If there is interest, for the next ARG meeting I could add
>> more details about the implementation requirements associated with this added
>> functionality, presuming I have captured it correctly.
>
> Well, I disagree. I think it's important if you want to program in a
> certain style. It makes certain patterns much more expressive. One
> example is the previous example of providing filters to iterators:
>
>     for Node of Tree.Search(function (N): N.Kind = Function_Call) loop
>         Do_Stuff;
>     end loop;
>
>
> If search is done in such a way that it returns an iterator object
> (which it should, because you might want to abort the search before
> the end), then it will need to take ownership of the lambda, or store
> a reference to it (depending on the semantics of the lambda objects).
>
> Another very common example is giving event handlers in event oriented
> programming:

I think perhaps you are trying to make lambdas solve all problems, when in fact
event handlers are quite naturally represented as objects with their dispatching
operations being the call backs.  There are some languages where all you have
are lambda expressions, and you end up using them for everything.  But for
languages that have support for dynamic dispatch already, the need for function
objects is much reduced in my view, and generalizing them too much is just
adding complexity and redundancy to the language definition.

In Java, I believe these might end up just being syntactic sugar around
declaring a new class with a single operation.  We could go in that direction
for Ada if we think it is important to be able to store these things, but I
think that is yet another step that seems even less important than being able to
return them.

I think you also have to think about the debugging problem.  You are effectively
creating large numbers of partial stack contexts, each of which is a potentially
very complex piece of state.  Trying to debug such a situation is much harder
than debugging a more data-object-based world, where the contents of the fields
of a record, or equivalent, represents the current state of things.  Yes it is
kind of cool that you can do all kinds of amazing things with lambdas, but I am
not convinced that is the clearest, most efficient, and most verifiable way to
solve the problem.  We should be really sure we need to add all of this
complexity on top of all the features already available for solving such
problems.

****************************************************************

From: Raphael Amiard
Sent: Thursday, October 13, 2016  1:21 PM

> I am not convinced we need to store these, so I would have to see the
> problem we are trying to solve.  I am sure you could construct an
> example that could take advantage of storing them, but I would suspect
> (hope?) that there are other ways of accomplishing the same thing
> without doing so.  I am not a big fan of burying everything in lambdas (as
> explained a bit more below).

Well, the problem is that you are then inventing a feature called lambda
functions that behaves slightly differently from the way it behaves in *every*
other languages that has lambda functions, because of implementation
considerations. I think the full version is implementable.

By the way, the event handler thing is a perfect example of why you would want
to store a closure object. It's a feature that has been asked many times by
users of GtkAda, both inside and outside of AdaCore.

> I think perhaps you are trying to make lambdas solve all problems,
> when in fact event handlers are quite naturally represented as objects
> with their dispatching operations being the call backs.  There are
> some languages where all you have are lambda expressions, and you end up
> using them for everything.

There are no such languages in wide use today, when even Scheme has a
standardized object system. However, there are a ton of languages (Python,
Javascript, OCaml, Scala, C++) where you could use one or the other, but where
people *consistently choose* to use lambda functions to do that kind of thing in
a certain subset of cases, because they are a much more expressive way of doing
the same thing, where all you can see as the reader of the code is the part of
the code that expresses the intent of the programmer.

>   But for languages that have support for dynamic dispatch already,
> the need for function objects is much reduced in my view, and
> generalizing them too much is just adding complexity and redundancy to the
> language definition.

Well, the fact that they added lambda functions to Java, and that they are
closures, is a good counter-argument to this. They could already do everything
with objects, but still decided to add lambdas. It does not mean we should add
them. However, in my view, it sure means that if we add them they should behave
consistently with user expectations however.

> In Java, I believe these might end up just being syntactic sugar
> around declaring a new class with a single operation.  We could go in
> that direction for Ada if we think it is important to be able to store
> these things, but I think that is yet another step that seems even
> less important than being able to return them.

Yes, in Java they implemented them as anonymous classes, which are closures, and
hence respect the expectations of the users regarding lambdas.

> I think you also have to think about the debugging problem.  You are
> effectively creating large numbers of partial stack contexts, each of
> which is a potentially very complex piece of state. Trying to debug
> such a situation is much harder than debugging a more
> data-object-based world, where the contents of the fields of a record,
> or equivalent, represents the current state of things. Yes it is kind
> of cool that you can do all kinds of amazing things with lambdas, but
> I am not convinced that is the clearest, most efficient, and most
> verifiable way to solve the problem.  We should be really sure we need
> to add all of this complexity on top of all the features already available for
> solving such problems.

That's a good point, but there are solutions to that that already exist. The
call to the lambda expression will appear in the context it is declared, where
you can naturally refer to the variables it closes over.

****************************************************************

From: Tucker Taft
Sent: Thursday, October 13, 2016  2:03 PM

>> I am not convinced we need to store these, so I would have to see the
>> problem we are trying to solve.  I am sure you could construct an
>> example that could take advantage of storing them, but I would
>> suspect (hope?) that there are other ways of accomplishing the same
>> thing without doing so.  I am not a big fan of burying everything in
>> lambdas (as explained a bit more below).
>
> Well, the problem is that you are then inventing a feature called
> lambda functions that behaves slightly differently from the way it
> behaves in *every* other languages that has lambda functions, because
> of implementation considerations. I think the full version is implementable.

I think you need to distinguish between garbage-collected languages where
everything of interest lives on the heap and has an indefinite lifetime, from
languages that attempt to keep most objects on a stack.  In C++11 they say you
are on your own from a safety point of view if you capture a "reference" to a
local variable.  So clearly there are more limitations when objects might be
stack based, or can't be copied.  Also, as you start expecting the compiler to
"do the right thing" and either complain or somehow automatically copy data that
is referenced, implementation expense goes up and the complexity of the
limitations from the user's perspective also grows.

I think a basic limitation such as treating these like objects of a limited type
that you can temporarily give a name either via rename or a build-in-place
declaration, but that you can't store in some global variable, might be
reasonable and would cover 90% of the cases of interest, without opening
ourselves up to the complexity of a C++-like solution.

> By the way, the event handler thing is a perfect example of why you
> would want to store a closure object. It's a feature that has been
> asked many times by users of GtkAda, both inside and outside of AdaCore. ...

I wonder whether some good syntactic sugar could make this work using tagged
types and single-operation interfaces.  This is not a case where you need to
construct the event handler dynamically and/or return it from a function.  You
just want an easy way to describe what happens when the event occurs, without
the heavy syntax burden of defining a new type with a new operation, and then
adding an appropriately initialized object of that type onto a list.

Another option I suppose might be to support something like an event channel.
You put your event channel on one or more lists, and then read from the channel
and write a simple "case" statement to handle the events as they arrive.

****************************************************************

From: Raphael Amiard
Sent: Thursday, October 13, 2016  2:28 PM

>> Well, the problem is that you are then inventing a feature called
>> lambda functions that behaves slightly differently from the way it
>> behaves in *every* other languages that has lambda functions, because
>> of implementation considerations. I think the full version is
>> implementable.
>
> I think you need to distinguish between garbage-collected languages
> where everything of interest lives on the heap and has an indefinite
> lifetime, from languages that attempt to keep most objects on a stack.
> In C++11 they say you are on your own from a safety point of view if
> you capture a "reference" to a local variable.

Yes, but you can still capture a value, so it makes all the relevant cases that
I talked about possible in C++11. For capturing references you use
smart-pointers, which are captured by value, but the value of a smart-pointer is
really a reference so all is well.

>   So clearly there are more limitations when objects might be stack
> based, or can't be copied.  Also, as you start expecting the compiler
> to "do the right thing" and either complain or somehow automatically
> copy data that is referenced, implementation expense goes up and the
> complexity of the limitations from the user's perspective also grows.

No, this is the way that it is supposed to work (capture by value). You have an
option for capture by reference in C++ but byval is always used in practice. If
you want reference semantics you use a smart-pointer.

> I think a basic limitation such as treating these like objects of a limited
> type that you can temporarily give a name either via rename or a
> build-in-place declaration, but that you can't store in some global variable,
> might be reasonable and would cover 90% of the cases of interest, without
> opening ourselves up to the complexity of a C++-like solution.

You can put an object of limited type in a global access variable, by allocating
the object dynamically. If we have such an option for lambdas, and make them
limited, then I'm 100% fine with that solution.

I think referencing outer variable needs to be treated like if those were
implicit

>>
>> By the way, the event handler thing is a perfect example of why you would
>> want to store a closure object. It's a feature that has been asked many times
>> by users of GtkAda, both inside and outside of AdaCore. ...
>
> I wonder whether some good syntactic sugar could make this work using tagged
> types and single-operation interfaces.

It could but raises several problems:

1. In C++ the equivalence works because you can overload the call operator. We
could provide something similar I guess, via an aspect for example.
2. The type of your closure, instead of being a special built-in access to
function type, then becomes a variadic generic function type. We don't have
variadic generics, and we'd still have to instantiate and name specific generic
for every closure instance, which is a pain.

Meta-point: This is IMHO the third time that it turns out that we have
weaknesses in the generic model that would force us to have built-in solutions
instead of hybrid library ones, or completely library ones:

1. The first is the type of generators.
2. The second is the type of lambda functions.
3. The third is the 'Reduce function/built-in.

>   This is not a case where you need to construct the event handler dynamically
> and/or return it from a function.  You just want an easy way to describe what
> happens when the event occurs, without the heavy syntax burden of defining a
> new type with a new operation, and then adding an appropriately initialized
> object of that type onto a list.

Well yeah indeed, but what you're doing is essentially a custom version of the
general lambda mechanism: Capturing the necessary variables, wrapping that in an
object with a call, and returning it as a function.

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, October 13, 2016  11:20 AM

> It seems what is being requested is the ability to write something
> like
> this:
>    function Filter(Pattern : String) return access function (X :
> String) return Boolean; This will return a filter which returns True
> only if X matches the pattern.

Indeed. Coincidentally, when Java came up with lambdas, this capability of
composing and returning functions, or using currying strategies to obtain
partially instantiated functions was THE major feature that at least one of our
industrial customer was heavily interested in. (I had a student doing a thesis
on Java lambdas for this customer - unfortunately not a good one.) And I see
what my functionally inclined grad students produce: heavy use of this
capability.

> Trying to write this:
>
>     function Filter(Pattern : String)
>       return access function (X : String) return Boolean is
>     begin
>         return (function (X) return Match(X, Pattern));
>     end Filter;
>
> This is do-able by treating such a result as living on the secondary
> stack, I suppose, which we would *not* cut back until the returned
> function is no longer being used.

Well, or have lambdas carry closures, i. e., a record of all values of free
variables at the time of lambda creation. Admittedly, this differs from Ada,
where up-level variables are referenced, not locally copied, but this is how
assignment-less functional languages operate. And, having references to anything
not global in a closure should be an accessibility violation - no exceptions.

Secondary stacks for all lambda creators in their textual region? Surely an
unbearable cost, especially when folks really get into recursive functional
programming.

****************************************************************

From: Tucker Taft
Sent: Thursday, October 13, 2016  11:48 AM

>> This is do-able by treating such a result as living on the secondary
>> stack, I suppose, which we would *not* cut back until the returned
>> function is no longer being used.
>
> Well, or have lambdas carry closures, i. e., a record of all values of
> free variables at the time of lambda creation. Admittedly, this
> differs from Ada, where up-level variables are referenced, not locally
> copied, but this is how assignment-less functional languages operate.

Particularly challenging when dealing with objects of a limited type.

> ... And,
> having references to anything not global in a closure should be an
> accessibility violation - no exceptions.

OK, so you are saying you cannot refer to local variables, only parameters and
globals, in a returned function expression?  Seems pretty limiting.  Basically
you have to put all of the computation inside the function expression itself,
which seems kind of unpleasant, especially if you have some computations you
could do once in advance, since they are independent of the parameters passed to
the function expression.

If we go that route, we should probably impose the same limitations as used by
access discriminants, requiring the use of "aliased" parameters if referring to
[in] out parameters, presuming that we are capturing the 'Access of all free
variables that we are not copying.  That is, we would have a block of 'Access
values for such free variables that was part of the representation of such a
function expression.

> Secondary stacks for all lambda creators in their textual region?
> Surely an unbearable cost, especially when folks really get into
> recursive functional programming.

It seems you could optimize by storing on the secondary stack only those things
that are actually referenced (directly or indirectly) in the returned function
expression.  I suggested, for simplicity, that you could put everything on the
secondary stack, but clearly you can do better than that.

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, October 13, 2016  2:48 PM

>> ... And,
>> having references to anything not global in a closure should be an
>> accessibility violation - no exceptions.
>
> OK, so you are saying you cannot refer to local variables, only
> parameters and globals, in a returned function expression?

No, you can of course refer to uplevel variables, but what you get is the value
that this entity held when the lambda was created. You do not get an opportunity
to assign to the original, because all you hold is a copy. If you assign (if
permitted at all??), then you change the copy.

Absent assignments, this semantics is indistinguishable from the Ada semantics
of uplevel addressing. With assignments to the up-level address inside or
outside, the semantics obviously differ.

Put differently, up-level variables are effectively cached locally, and that is
the semantics of the new feature called lambdas.

The accessibility issue arises when said value is in turn a reference, e.g. the
code refers to an up-level variable of access type, which in turn references
something. The reference value copied from the local variable better be to a
global entity, nothing else. (One could refine this, but the rules will be as
inscrutable as today's accessibility rules.)

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, October 13, 2016  4:23 PM

>>     function Filter(Pattern : String)
>>       return access function (X : String) return Boolean is
>>     begin
>>         return (function (X) return Match(X, Pattern));
>>     end Filter;

more on Syntax (and Semantics): I am not so sure that I like the lambda to be
returned typed as an access function ...., implying that it can be assigned to
some variables, hooked into dispatch vectors, etc.

I would much prefer an ability to name, but not necessarily to assign these
values. E.g.,

     function Filter(Pattern : String)
       return function (X : String) return Boolean is
     begin
         return (function (X) return Match(X, Pattern));
     end Filter;

and if anybody wants a name for the lambda:

function ParisMatch(X : String) return Boolean is Filter("Paris");

****************************************************************

From: Tucker Taft
Sent: Tuesday, February 27, 2018  6:32 PM

I have added wording to this AI on "function expressions". [This is version
/04 of the AI - ED.]

****************************************************************

From: Brad Moore
Sent: Friday, March 2, 2018  11:32 PM

I like the idea of function expressions overall. I have just a couple of
comments.

>> We are only supporting defining anonymous functions using this
>> proposed "function_expression" construct.  Anonymous procedures are
>> nicely handled with the loop-body proposal (AI12-0189).

Not really. The loop-body proposal only applies to a limited subset of cases
where anonymous procedures could be used. Those where the anonymous procedure
is the body of the loop. Not all anonymous procedures fit this use case.

For example, for 'Reduce we were talking about allowing a reducer in the form
of a procedure of the form;
    procedure Reduce (L : in out Item, R : Item);

which might be appropriate when Item is a large matrix type.

It might be nice to write a combiner function as a function expression in some
cases, for instance, which I presume would be allowed by the AI, (for
combiners that are functions). Similarly, I presume one could use function
expressions for generic actuals when instantiating a generic.

eg. See below

>> In any case, mixing
>> statements inside expressions seems like a bad idea.  Also, we don't
>> have "expression procedures" so it doesn't seem so bad that we don't
>> have "procedure expressions" ;-).

This seems like the better argument.

>> !example
>>
>>    --  Replace control chars with '?'
>>    Ada.Strings.Fixed.Translate
>>      (Str, (function (C) return (if C < ' ' then '?' else C)));
>>
>>    --  Procedure for plotting a function
>>    procedure Plot_Graph
>>      (Fun : access function (X : Float) return Float;
>>       Start, Stop : Float);
>>
>>    ...
>>
>>    --  Plot a graph of X-squared from 1 to 20
>>    Plot_Graph (Fun => (function (Z) return Z**2),
>>                Start => 1.0, Stop => 20.0);
>>

I have another example for consideration.

   subtype Degrees is Integer;

   -- Instantiate a list of degree values of a circle, eg. -1 = 359 = 720
   package Degree_Lists is new
     Ada.Containers.Doubly_Linked_Lists (Element_Type => Degrees,
                                         "="          => (function (L, R) return (L mod 360 = R mod 360)));

****************************************************************

From: Randy Brukardt
Sent: Wednesday, December 12, 2018  6:08 PM

I put AI12-0190-1 into the draft RM last night, which rekindled all of my real
objections to that proposal, and contrasted it against the FUD that was used to
kill the much more valuable (IMHO) generic type defaults. [There is absolutely
nothing new in the implementation of generic type defaults, all of the potential
issues already exist in a similar form in existing generic
declarations/instantiations. Obviously, anything can be an issue for a specific
implementation (especially if a hack was used to implement something), but
AI12-0205-1 is among the least likely to have such an issue. OTOH, the
implementation of function expressions has several new things which potentially
cause issues - it is a much more reasonable candidate to worry about
implementation cost. And, it mainly is a writing aid, at best, readability is a
wash, where one has traded the declaration of an extra name for a nested
construct (which necessarily makes the outer construct harder to read) and Lots
of Irritating Stupid Parentheses :-).]

Anyway, that's settled but I'll keep griping about it for years. :-)

However, in thinking about the implementation problems, I started wondering how
it is supposed to work when it appears in any sort of default expression. In
particular, consider:

   package Pack is
      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural;
   end Pack;

   package body Pack is
      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural is ...
   end Pack;

   with Pack;
   procedure Main is
      V : Natural := Pack.Ugh;
   begin
      Put (V'Image);
   end Main;

Questions:
   (1) Do we have rules to deal with function expressions in conformance? In
      particular, don't we need rules about the conformance of the formal parts?
      (Two paragraphs of semantics for this feature is clearly too good to be
      true. :-(  )
   In particular, we wouldn't want the body to differ. But which of these differ (or should differ) and why?
      [A] function Ugh (P : Natural := Foo ((function (B) return B*2), 2)) return Natural is ...
      [B] function Ugh (P : Natural := Foo ((function (A : Natural) return A*2), 2)) return Natural is ...
      [C] function Ugh (P : Natural := Foo ((function (A) return B*3), 2)) return Natural is ...
   Clearly [C] had better fail conformance, but what about the others?

   (2) The rule about evaluating a function expression says that a function
       expression "... is equivalent to a local expression_function_declaration
       ...". But local where?
      [A] The first occurrence (the specification of Pack);
      [B] Both occurrences (both the specification and body of Pack -- this would imply that they never conform).
      [C1] At the point of use (in the body of Main), with names resolved at the first point of occurrence;
      [C2] At the point of use (in the body of Main), with names resolved at the point of use.
    Default expressions can also occur in record declarations and generic in
    parameters, so even saying that these never conform does not eliminate the
    question.

    The wording is mainly "Static Semantics", which would imply [B], but that of
    course would require doing some code generation for default expressions at
    the point of declaration [I know the Janus/Ada can't do that as currently
    designed]. And it also would prevent any conformance (since there'd be two
    separate functions declared by the two declarations, which could never be
    allowed).

Thoughts?

P.S. I found and fixed a place in the AI where "expression_function" was used
instead of "function_expression". Luckily the former isn't actually a thing
(that's "expression_function_declaration"), so I got a formatting error and
caught it. This naming will drive us nuts. Grump.

****************************************************************

From: Steve Baird
Sent: Wednesday, December 12, 2018  7:09 PM

> Do we have rules to deal with function expressions in conformance? In
> particular, don't we need rules about the conformance of the formal parts?

We've got the conformance rule that was added in AI12-0050, motivated by
quantified expressions:

    each [blah] in one denotes the same
    declaration as the corresponding [blah] in the other,
    or they denote corresponding declarations
    occurring within the two expressions; and

So I think all that is needed here is a friendly (but not unreasonably so)
reading of the word "corresponding".

I don't think any RM wording changes are needed to deal with this issue.

If the two versions differ syntactically (e.g., your completion [B], which
explicitly names the parameter subtype when the first default expression did
not), then they don't conform. I think that follows from 6.3.1(20)'s "same
syntactic category" wording.

>
>    (2) The rule about evaluating a function expression says that a
> function expression "... is equivalent to a local
> expression_function_declaration ...". But local where?

That's a good question and it looks to me like we do need some wording here (but
I didn't review the AI carefully with this question in mind - if Bob explains
that there is really no problem here and this is already handled very nicely, I
won't be surprised).

I think that, roughly speaking, we'd like something along the lines of
    first, find the nearest enclosing statement or declaration.
    if it is a declaration, then the implicit subprogram declaration goes
    immediately ahead of that declaration.
    if it is a statement, then wrap an implicit block statement around
    that statement and put the implicit declaration in the declarative
    part of that block statement.

I think this is the model we want for dynamic semantics and for static
accessibility checking, although hopefully expressed with better wording than
the above. And this approach may need to be extended to handle cases like a
generic formal subprogram default which contains references to earlier generic
formal parameters.

The key idea is that there should be a (hopefully straightforward) equivalence
rule for defining this new construct in terms of old code that does not contain
this new construct.

But can one of these guys reference, for example, the identifier of a quantified
expression (or the defining identifier of an iterated component association, or
...)?

     (for all Idx in Vec'Range =>
        Foo ((function (J) return J <= Idx), 2))
         --  Is the use of Idx legal?

If so, then the model I sketched out breaks down and things are more
complicated.

I don't think we want to allow this case, but that's just my opinion.

It does sound like some more discussion of this (approved) AI is needed.

****************************************************************

From: Tucker Taft
Sent: Wednesday, December 12, 2018  9:04 PM

> ...
>    (for all Idx in Vec'Range =>
>       Foo ((function (J) return J <= Idx), 2))
>        --  Is the use of Idx legal?
>
> If so, then the model I sketched out breaks down and things are more
> complicated.
>
> I don't think we want to allow this case, but that's just my opinion.

I am not sure.  This seems to be a fairly natural use of this feature.  I would
be reluctant to start adding complicated restrictions in what names can be
mentioned in the expression without a good reason.

I am not sure we need to provide too prescriptive a definition of the
implementation approach.  I would hope that the expression's name resolution
should have visibility on the innermost declarative region, independent of
whether that is a declare block, a loop, or an iterator.  That is pretty much
how names work in most cases, and I don't think we should change that for these.
Carving holes into the enclosing visibility seems like bad news in many ways.

As far as accessibility, if a function expression is used as a generic actual or
in a rename, "local" is quite well defined.  For a parameter of a function call,
the master that evaluated the construct can provide a well-defined accessibility
level for such a "local" function, meaning that it would be fine for an
anonymously-typed access-to-subprogram parameter, but would never match a
parameter of a named access-to-subprogram type.

> It does sound like some more discussion of this (approved) AI is needed.

It sounds like we might need a mild tweak to the conformance rules. But I am
reluctant to try to spell out the implementation model in great detail.  All
names visible at the point of the construct should be usable, and maybe the
simplest thing to do about accessibility is to only allow these to match the
anonymous access type of a function parameter, and steer clear of all named
access types or anonymous access types in other contexts.

Accordingly, here are some adjustments to AI12-0190-1, using our usual [...] and
{...}:

             Name Resolution

  In a context where there is an expected type rather than an expected
  profile for a function_expression, the expected type shall be a single
  {anonymous} access-to-function type, and the profile of this type is considered
  the expected profile for the function_expression.  The result type of
  the expected profile of the function_expression is the expected type
  for the expression of the function_expression. If there is no
  function_formal_parameter_list, the expected profile shall have no
  parameters.  If the function_formal_parameter_list is a formal_part,
  then it shall be subtype conformant to the expected profile if there
  is an expected type, or merely mode conformant otherwise.  If the
  function_formal_parameter_list is a sequence of identifiers, the
  number of identifiers in the sequence shall be the same as the number
  of formal parameters in the expected profile.

{           Legality Rules

When used in a context where there is an expected type, the function_expression
shall be an actual parameter in a call, or a parameter default for a callable
entity, where the corresponding formal is of an anonymous access-to-subprogram
type.}

           Static Semantics

  A function_expression used in a context where there is an expected
  type is equivalent to [a local] {an} expression_function_declaration
  (see 6.8) {declared within the innermost enclosing declarative region},
  with the function_expression replaced by an Access
  attribute_reference of this locally defined function; otherwise, the
  function_expression is equivalent to such a local declaration with the
  function_expression replaced by a name denoting this locally defined
  function.  The profile of this locally defined function has a result
  type determined by the expected profile, and a formal part determined
  by the formal_part, if provided in the expression_function, or by the
  formal part of the expected profile otherwise, but with the name of
  each formal parameter of the expected profile replaced by the
  corresponding identifier in the sequence of identifiers.  The expression
  of this locally defined expression function is that of the
  function_expression.

 {AARM To Be Honest: Depending on the nature of the innermost enclosing
  declarative region, this equivalence might violate the normal syntax rules
  which would not permit such an expression_function_declaration in such a
  region.}

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  11:41 AM

>    (1) Do we have rules to deal with function expressions in
>    conformance?

I agree with Steve that the current wording is good enough.
Feel free to add some examples to the AARM to clarify.

> ... In
> particular, don't we need rules about the conformance of the formal parts?
> (Two paragraphs of semantics for this feature is clearly too good to
> be true. :-(  )
>    In particular, we wouldn't want the body to differ. But which of
> these differ (or should differ) and why?
>       [A] function Ugh (P : Natural := Foo ((function (B) return B*2), 2)) return Natural is ...
>       [B] function Ugh (P : Natural := Foo ((function (A : Natural) return A*2), 2)) return Natural is ...
>       [C] function Ugh (P : Natural := Foo ((function (A) return B*3), 2)) return Natural is ...
>    Clearly [C] had better fail conformance, but what about the others?

A and B should not conform, IMHO.  And of course I agree about C.

>    (2) The rule about evaluating a function expression says that a
> function expression "... is equivalent to a local
> expression_function_declaration ...". But local where?

It bothers me that if you instantiate a generic package in a package spec, the
instance body occurs in the package spec, even though that's syntactically
illegal.  But we've lived with that for decades.

This case doesn't bother me any more than that, so I can live with it.  Tucker's
wording seems OK.

>       [A] The first occurrence (the specification of Pack);

Yes.

>       [B] Both occurrences (both the specification and body of Pack --
> this would imply that they never conform).

That would be unfortunate -- default values are a fairly natural place to use this feature.

>       [C1] At the point of use (in the body of Main), with names
> resolved at the first point of occurrence;

No.

>       [C2] At the point of use (in the body of Main), with names
> resolved at the point of use.

No, NO, NO!  ;-)

>     Default expressions can also occur in record declarations and
> generic in parameters, so even saying that these never conform does
> not eliminate the question.

Right.  And I don't like the "never conform" option anyway.

>     The wording is mainly "Static Semantics", which would imply [B],
> but that of course would require doing some code generation for
> default expressions at the point of declaration [I know the Janus/Ada
> can't do that as currently designed]. And it also would prevent any
> conformance (since there'd be two separate functions declared by the
> two declarations, which could never be allowed).

It seems to me you can generate code whereever/whenever you like, regardless of
what the RM says.

> Thoughts?
>
> P.S. I found and fixed a place in the AI where "expression_function"
> was used instead of "function_expression". Luckily the former isn't
> actually a thing (that's "expression_function_declaration"), so I got
> a formatting error and caught it. This naming will drive us nuts. Grump.

I agree -- having "expression function" and "function_expression" mean two
different things is intolerable.  I think we had better change the name.  (We
don't have "expression_function", but we do have "expression function").

Ideas: function_literal, literal_function, lambda, lambda_function.

It's probably too late to do it the other way around (e.g. change
"expression_function_declaration" to "shorthand_function_declaration".

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  11:41 AM

> I think that, roughly speaking, we'd like something along the lines of
>     first, find the nearest enclosing statement or declaration.
>     if it is a declaration, then the implicit subprogram declaration goes
>     immediately ahead of that declaration.
>     if it is a statement, then wrap an implicit block statement around
>     that statement and put the implicit declaration in the declarative
>     part of that block statement.

I don't think we want something like that in the RM.  I find the wording in the
AI, or perhaps Tuckers wording, preferable.

It's appalling that 6.3.1 has grown from 6 clear paragraphs in Ada 83 (not
counting NOTES) to 37 impenetrable paragraphs in Ada 2012. Let's not continue on
that path.  ;-)

> But can one of these guys reference, for example, the identifier of a
> quantified expression (or the defining identifier of an iterated
> component association, or ...)?
>
>      (for all Idx in Vec'Range =>
>         Foo ((function (J) return J <= Idx), 2))
>          --  Is the use of Idx legal?

I think it should be.

But it's worse than you imply, because what if there's another Idx declared
outside this?  We certainly don't want Idx to denote that outer thing.  That
would introduce something like the infamous "with statement" language design
flaw that exists in Pascal.

I could (barely) tolerate making these things illegal inside "for all", but as
Tuck said, it's a pretty natural thing to want to do.

> It does sound like some more discussion of this (approved) AI is needed.

Sigh.

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  12:29 PM

>              Name Resolution
>
>   In a context where there is an expected type rather than an expected
>   profile for a function_expression, the expected type shall be a single
>   {anonymous} access-to-function type
> ...
> {           Legality Rules
>
> When used in a context where there is an expected type, the
> function_expression shall be an actual parameter in a call, or a
> parameter default for a callable entity, where the corresponding
> formal is of an anonymous access-to-subprogram type.}

Isn't the part starting ", where" redundant with the Name Res rule?

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  1:20 PM

Yes, good point.  When I wrote it I thought there was something still not
implied by the Name Res rules, but now I agree with you, the phrase can be
dropped.

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  1:45 PM

>  I think we had better change the
> name.  (We don't have "expression_function", but we do have
> "expression function").
>
> Ideas: function_literal, literal_function, lambda, lambda_function.

I like "function_literal," analogous to string_literal.

I could see "lambda_expression" though the word "lambda" kind of comes out of
thin air for the reader who doesn't recognize the term.

Here is WikiPedia's entry on this concept:

"In computer programming, an anonymous function (function literal, lambda
abstraction, or lambda expression) is a function definition that is not bound to
an identifier. Anonymous functions are often arguments being passed to
higher-order functions, ..."

It seems worth picking one from their list, if we decide to go away from
"function_expression" (which I think is still OK, FWIW), rather than inventing
yet another Ada-specific term.

So "function_literal," "anonymous_function," and "lambda_expression" all seem
reasonable alternatives to "function_expression.

****************************************************************

From: Gary Dismukes
Sent: Thursday, December 13, 2018  2:29 PM

> I like "function_literal," analogous to string_literal.

That one doesn't appeal to me.  In Ada, literals are single tokens.

> I could see "lambda_expression" though the word "lambda" kind of comes out
>of thin air for the reader who doesn't recognize the term.
>
> Here is WikiPedia's entry on this concept:
>
> "In computer programming, an anonymous function (function literal, lambda
> abstraction, or lambda expression) is a function definition that is not
> bound to an identifier. Anonymous functions are often arguments being
> passed to higher-order functions, ..."
>
> It seems worth picking one from their list, if we decide to go away from
> "function_expression" (which I think is still OK, FWIW), rather than
> inventing yet another Ada-specific term.
>
> So "function_literal," "anonymous_function," and "lambda_expression" all
> seem reasonable alternatives to "function_expression.

Anonymous_function seems reasonable.  I could live with function_expression, but
it does potentially create confusion with expression functions, so I think we
should change it if we can agree on another name.

****************************************************************

From: Tullio Vardanega
Sent: Thursday, December 13, 2018  2:37 PM

What about "a lambda expression, that is, is a function definition that is not
bound to an identifier"?

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  3:00 PM

> I could see "lambda_expression" though the word "lambda" kind of comes
> out of thin air for the reader who doesn't recognize the term.

Doesn't every programmer learn at least a small amount of Lisp in their
"Comparative Programming Languages" course?

> Here is WikiPedia's entry on this concept:
>
> "In computer programming, an anonymous function (function literal,
> lambda abstraction, or lambda expression) is a function definition
> that is not bound to an identifier. Anonymous functions are often
> arguments being passed to higher-order functions, ..."
>
> It seems worth picking one from their list, if we decide to go away
> from "function_expression" (which I think is still OK, FWIW), rather
> than inventing yet another Ada-specific term.

Good point.  I hate when languages get creative with their terms when everybody
else already has a perfectly good term.

Or three.  ;-)

> So "function_literal," "anonymous_function," and "lambda_expression"
> all seem reasonable alternatives to "function_expression.

I'm happy with all three of those.  My favorite is "anonymous_function".

I really think having both "expression function" and "function_expression" is
confusing -- embarrassingly so.

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  3:07 PM

The term "anonymous" is already used in several contexts in Ada, so using it for
these sorts of functions seems pretty appropriate and consistent.  I like
"lambda expression" except for the fact it introduces the term "lambda" into the
language and a chapter called "Lambda Expressions" would be pretty mysterious to
programmers who have not taken that "Comparative Programming Languages" course
(alas, I suspect that is many "programmers" these days).  It would be easy for
any Ada user to guess what is going on in a chapter called "Anonymous
Functions."

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  3:56 PM

...
> It does sound like some more discussion of this (approved) AI is
> needed.

This seems like a "reopen" rather than a "fix-up" situation, because (A) there
is a lot of issues that were not resolved - including the name of the thing, (B)
resolving those issues might cause people to change their vote on the feature as
a whole (that is, it originally looked very simple, but it is not looking so
simple now), and (C) it might take more time than we have to resolve these
issues. (Admittedly, (C) probably won't be the case, but fixing this AI could
take time from more important things below it on the agenda [for example,
Bignums].)

Does anyone second reopening this AI?

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  4:05 PM

> > I don't think we want to allow this case, but that's just
> my opinion.
>
> I am not sure.  This seems to be a fairly natural use of this feature.
> I would be reluctant to start adding complicated restrictions in what
> names can be mentioned in the expression without a good reason.

Well, a natural implementation of this quantified expression puts Idx into a
register temporary. External code, like this function here, would have no way to
access such an Idx, as it would have no access to how the register temporary
ends up getting mapped by the code generator (to a hardware register, to a spill
location, or some combination).

So the implementation would to recognize this special case and allocate a real
memory location for it. (You would not want to do that in general, as you want
the loop parameter to be stored in a register rather than memory if possible.
Using a register temporary eliminates the need for the code generator to keep
the memory location up-to-date.) Moreover, that location would be dead in the
function body, since the memory location would be given the lifetime of the
expression (and presumably reused elsewhere). So there would need to be some
special mechanism to "re-animate" the memory location in the function body.

I'm sure that some solution can be found, but it would be a significant
complication to the implementation.

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  4:15 PM

> > I think that, roughly speaking, we'd like something along the lines of
> >     first, find the nearest enclosing statement or declaration.
> >     if it is a declaration, then the implicit subprogram declaration goes
> >     immediately ahead of that declaration.
> >     if it is a statement, then wrap an implicit block statement around
> >     that statement and put the implicit declaration in the declarative
> >     part of that block statement.
>
> I don't think we want something like that in the RM.  I find the
> wording in the AI, or perhaps Tuckers wording, preferable.

It might be preferable, but it makes it hard or impossible to answer questions
about details of the function. If we have to answer those one-by-one as someone
thinks of them, the entire thing gets tiresome (and we *still* end up with a
bunch of wording).

For instance, the contracts that apply to this function depend on where it is
declared (since they can't be given explicitly -- and if someone proposes that
we allow that, then this proposal has definitely jumped the shark). Consider:

   package Pack
      with Nonblocking => False is

      function Foo (A : access function (B : Natural) return Natural) return Natural
         with Nonblocking => True;

      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural
         with Nonblocking => True;

   end Pack;

Is this default expression legal? (This is roughly the structure of Text_IO,
lest someone find it unlikely.)

That depends on where the anonymous function is declared. If it outside of Ugh,
then it has Nonblocking => False, and the 'Access is illegal (a potentially
blocking subprogram can't be designed by a nonblocking access type for obvious
reasons).

I suppose we could adopt a special rule for this case, but then there is a
similar case for Global. (At least, there better be, I haven't look carefully at
the rules. But an access type that promises no access to globals have better not
designate a subprogram that accesses globals.) So yet another rule would needed
to deal with that. And are those the only such cases? Hard to know.

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  4:48 PM

> Does anyone second reopening this AI?

I second the motion.

Who is in charge of this AI?
I'm willing to do a rewrite, if we can agree on "anonymous_function", and if
whoever is in charge doesn't want to do it.

Re: (B) above: I never thought this feature was simple in terms of
implementation.  It's pretty simple conceptually, though.

I note that the subject is:

!subject Anonymous functions

And it says:

    We considered other names such as "lambda functions," "function
    literals," and "anonymous functions."  We ultimately went with "function
    expression" as it seemed analogous to "if expression" and "case
    expression," though there is admittedly some discomfort in having both
    "expression functions" and "function expressions."

This is exactly the Ada-centric thinking that Tucker and I expressed dislike
for:

>> It seems worth picking one from their list ...rather than inventing
>> yet another Ada-specific term.
>
> Good point.  I hate when languages get creative with their terms when
> everybody else already has a perfectly good term.

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  4:51 PM

> ...
> For instance, the contracts that apply to this function depend on
> where it is declared (since they can't be given explicitly -- and if
> someone proposes that we allow that, then this proposal has definitely jumped
> the shark).

The wording fix I proposed replaced "local" with "within the innermost
declarative region." That seems to answer this question unambiguously.

> Consider:
>
>   package Pack
>      with Nonblocking => False is
>
>      function Foo (A : access function (B : Natural) return Natural) return Natural
>         with Nonblocking => True;
>
>      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural
>         with Nonblocking => True;
>
>   end Pack;
>
> Is this default expression legal? (This is roughly the structure of
> Text_IO, lest someone find it unlikely.)
>
> That depends on where the anonymous function is declared. If it
> outside of Ugh, then it has Nonblocking => False, and the 'Access is
> illegal (a potentially blocking subprogram can't be designed by a
> nonblocking access type for obvious reasons).

The wording as amended proposes the innermost declarative region, which in this
case is Ugh.  The TBH makes it clear that this innermost declarative region need
not be something that normally would allow such declarations.

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  4:52 PM

> Who is in charge of this AI?
> I'm willing to do a rewrite, if we can agree on "anonymous_function",
> and if whoever is in charge doesn't want to do it.

I am the author, and am happy to update it.

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  5:05 PM

...
> >    (2) The rule about evaluating a function expression says that a
> > function expression "... is equivalent to a local
> > expression_function_declaration ...". But local where?
>
> It bothers me that if you instantiate a generic package in a package
> spec, the instance body occurs in the package spec, even though that's
> syntactically illegal.  But we've lived with that for decades.

You mean that you've thought of a generic instantiation incorrectly for decades.
;-) If you have a shared generic, clearly the body doesn't live there (only a
call to elaborate it). That indeed was one of the reasons that we thought early
on that Ada (83) was designed with the intent of generic sharing. (The others
being the contract model and the inadvisability of compilation dependences --
especially back then, in the days of 5 minute compilations per unit.)

> This case doesn't bother me any more than that, so I can live with it.
> Tucker's wording seems OK.

That wasn't my point. My point was that the location of the declaration
determines some of its properties (accessibility, contracts, probably more), so
we need to know where it is. *Especially* in which compilation unit it exists.
Ada goes to substantial lengths to say where operators and other implicit things
are declared. It would be very unusual for this declaration to be essentially
declared anywhere that you feel like it. (Probably the only such thing in Ada.)

Note that the point of the declaration and the point of the body don't have to
be the same. The point of the declaration has to be nailed down, IMHO. The
location of the body could possibly be left up to the implementation.

> >       [A] The first occurrence (the specification of Pack);
>
> Yes.
>>       [B] Both occurrences (both the specification and body of Pack
>> -- this would imply that they never conform).
>
>That would be unfortunate -- default values are a fairly natural place
>to use this feature.
...
> >     The wording is mainly "Static Semantics", which would imply [B], ...

[A] would be different than every other feature in a subprogram specification.
Anonymous access types are different (and then there are matching rules);
quantified expression (and soon declare expressions) objects are different (and
then there are matching rules), and so on.

Either you would have to come up with a newly invented semantics where the
function *isn't* duplicated even though there are two distinct expressions, or
we need an additional conformance rule to allow this case. Either way, we need
an additional rule.

> > but that of course would require doing some code generation for
> > default expressions at the point of declaration [I know the
> > Janus/Ada can't do that as currently designed]. And it also would
> > prevent any conformance (since there'd be two separate functions
> > declared by the two declarations, which could never be allowed).
>
> It seems to me you can generate code whereever/whenever you like,
> regardless of what the RM says.

Well, maybe your compiler can. I realize arguments from implementation
difficulty are weak, but after a very valuable proposal (AI12-0205-1) got
scuttled because of FUD from an implementer, please bear with me. :-)

Janus/Ada is primarily a syntax-directed translator in the form of the (green,
original) dragon book. That's in part because it started in a class where that
organization was required. Regardless, it still remains primarily implemented
with action routines tied to reductions of syntax productions. We had to move to
trees for expression analysis, but almost everything else remains implemented
syntactically, in particular all declarations, including subprograms, types,
packages, etc.

The Janus/Ada intermediate code was also designed around the needs of Ada
(originally Ada 83), as well as the needs of optimization, interpretation, and
code generation. It rarely allows things that aren't needed by Ada (in
particular, it doesn't allow function calls that need to copy back parameters, a
long-standing problem for interfacing and now "in out" parameters). Relevant to
this case, it does not allow declarations unless they're at the outer level of
the intermediate code (dubbed "prairie points" because there cannot be any trees
- not my doing). So many "natural" points of code generation cannot declare a
subprogram (or many other things). (And honestly, I can't see how that would
work in anyone's intermediate form -- splitting an expression in half would make
it hard/impossible to optimize.)

For a long time, I tried to allow code generation at freezing points. But there
always was another case where code was getting generated somewhere it couldn't
be. I eventually gave up and delayed all of that until the end of the
declarative part when everything is frozen anyway. (Since most of that code is
thunk bodies, where they are generated is essentially irrelevant. But it does
lead to a large gob of undifferentiated code at the foot of every package, which
is hell to look at when something goes wrong.)

Anyway, delaying the generation of something is not particularly hard, but
generating or even declaring it early is impossible in Janus/Ada. There probably
is some solution involving generating the declaration in one place and the body
much later, but that will require an entirely new mechanism in the compiler and
potentially extra tree passes as well (or general changes to some existing tree
pass to deal with this unusual case). The implementation will be quite expensive
- even if we don't have to deal with quantified expression loop parameters.

Aside: Robert once complained that this organization is "very inflexible". He's
right, but that was a huge advantage for us in the early days. Back when most of
Janus/Ada was built, we were undisciplined straight-out-of-university
know-it-alls (what person in their early 20s isn't that???). Had we had a blank
page organization, hardly anything would have worked. Even now, the tree-based
stuff is much harder to work on than the syntax-directed parts. (And the tree
based stuff wasn't even built until we'd learned various lessons about
organization the hard way.)

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  5:08 PM

> I am the author, and am happy to update it.

OK, thanks!

Anybody object to "anonymous function"?
Speak now or forever hold your peace.  ;-)

Some AARM examples might help clarify things.

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  5:08 PM

...
> > Does anyone second reopening this AI?
>
> I second the motion.
>
> Who is in charge of this AI?

Tucker was the author.

> I'm willing to do a rewrite, if we can agree on "anonymous_function",
> and if whoever is in charge doesn't want to do it.

Tucker has plenty else to do -- he took all of the homework from our last
meeting.

> Re: (B) above: I never thought this feature was simple in terms of
> implementation.  It's pretty simple conceptually, though.
>
> I note that the subject is:
>
> !subject Anonymous functions
>
> And it says:
>
>     We considered other names such as "lambda functions," "function
>     literals," and "anonymous functions."  We ultimately went with "function
>     expression" as it seemed analogous to "if expression" and "case
>     expression," though there is admittedly some discomfort in having both
>     "expression functions" and "function expressions."
>
> This is exactly the Ada-centric thinking that Tucker and I expressed
> dislike for:
>
> >> It seems worth picking one from their list ...rather than inventing
> >> yet another Ada-specific term.
> >
> > Good point.  I hate when languages get creative with their terms
> > when everybody else already has a perfectly good term.

This must have been Tucker version 2. Tucker version 1 was the author of the
AI and clearly of the paragraph you read above. I'm soooo confused. :-)

****************************************************************

From: Gary Dismukes
Sent: Thursday, December 13, 2018  5:11 PM

> The term "anonymous" is already used in several contexts in Ada, so using it
> for these sorts of functions seems pretty appropriate and consistent.  I
> like "lambda expression" except for the fact it introduces the term "lambda"
> into the language and a chapter called "Lambda Expressions" would be pretty
> mysterious to programmers who have not taken that "Comparative Programming
> Languages" course (alas, I suspect that is many "programmers" these days).
> It would be easy for any Ada user to guess what is going on in a chapter
> called "Anonymous Functions."

Strongly agreed.  I much prefer "anonymous functions" over "lambda expressions".

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  5:32 PM

...
>>And it says:
>>
>>   We considered other names such as "lambda functions," "function
>>   literals," and "anonymous functions."  We ultimately went with "function
>>   expression" as it seemed analogous to "if expression" and "case
>>   expression," though there is admittedly some discomfort in having both
>>   "expression functions" and "function expressions."

>> This is exactly the Ada-centric thinking that Tucker and I
>> expressed dislike for:

Guilty as charged.

>>>It seems worth picking one from their list ...rather than inventing
>>>yet another Ada-specific term.
>>
>>Good point.  I hate when languages get creative with their terms when
>>everybody else already has a perfectly good term.
>
>This must have been Tucker version 2. Tucker version 1 was the author of the
>AI and clearly of the paragraph you read above. I'm soooo confused. :-)

Makes me remember fondly good old Norm Cohen prime and double-prime ... ;-)

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  5:47 PM

> > ...
> > For instance, the contracts that apply to this function depend on
> > where it is declared (since they can't be given explicitly -- and if
> > someone proposes that we allow that, then this proposal has
> > definitely jumped the shark).
>
> The wording fix I proposed replaced "local" with "within the innermost
> declarative region." That seems to answer this question unambiguously.

Sorry, I didn't see that proposal. I only saw a proposed Legality Rule to
disallow these matching named access types (which only fixes a small corner of
the proposal).

...
> The wording as amended proposes the innermost declarative region,
> which in this case is Ugh.  The TBH makes it clear that this innermost
> declarative region need not be something that normally would allow
> such declarations.

Ugh! :-) That means that invariants throughout the compiler will fail seemingly
at random when compiling these things. Another substantial implementation
expense.

Mildly related: I recently spent more than a day fixing several dozen invariant
failures caused by allowing anonymous access-to-subprogram types in parameters.
Originally, those were rejected as soon as they appeared syntactically as being
unimplemented ("feature not implemented", or FNI). But that caused them to be
replaced by "Integer" (the default correction for bad types) and that caused a
lot of error cascades. I thought that if I declared the type and then FNIed any
uses there would be fewer cascades. I also thought that would be easy (famous
last words).

However, declaring the type required a TYP node (it would have been called
"TYPE" but declaring an enumeration literal with that name doesn't work for some
reason :-) in the symboltable in order to be an anchor for the parameter list of
the anonymous access-to-subprogram (otherwise, the parameter lists would have
gotten co-mingled, and that clearly wouldn't have worked). And it turned out
that pretty much every piece of code that walked a parameter list (and there
were many) had been written to our style guide and looked something like:
   while Param_Ptr /= null loop
      case Param_Ptr.Selector is
         when PARAM => ... -- Do whatever good things.
         when others =>
              Internal_Error ("Not a parameter in a parameter list!");
      end case;
      Param_Ptr := Param_Ptr.Next;
   end loop;

I had to add
    when TYP => -- Probably an anonymous-access-to-subprogram parameter is next.
        null; -- Skip this.
to every one of those loops (and I've probably missed some until I compile the
right example).

This sounds like that problem all over again.

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  5:47 PM

Here is an update incorporating some of these discussions. [This is version /06
of the AI - Editor.]

****************************************************************

From: Bob Duff
Sent: Thursday, December 13, 2018  5:59 PM

> Here is an update incorporating some of these discussions.

Thank you!  Looks good, except:

> Add section after 4.5.8:
>
>   4.5.9 Function Expressions
>
>   Function expressions provide a way to define a function at a point

Oops.  Our esteemed editor can no-doubt correct that.

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018   6:23 PM

> > ...
> > > It does sound like some more discussion of this (approved) AI is
> > > needed.
> >
> > This seems like a "reopen" rather than a "fix-up" situation, because
> > (A) there is a lot of issues that were not resolved - including the
> > name of the thing, (B) resolving those issues might cause people to
> > change their vote on the feature as a whole (that is, it originally
> > looked very simple, but it is not looking so simple now), and (C) it
> > might take more time than we have to resolve these issues.
> > (Admittedly, (C) probably won't be the case, but fixing this AI
> > could take time from more important things below it on the agenda
> > [for example, Bignums].)
...
> Re: (B) above: I never thought this feature was simple in terms of
> implementation.  It's pretty simple conceptually, though.

I agree in that I never thought it was simple, either. But it now is looking
like a nightmare, especially in corner cases (where the function accesses outer
expression objects - quantified/declare). I certainly didn't think about the
implementation in any detail until I was in the shower the other day. I was
thinking about your argument about the complications of implementing
declare_expressions for all of the corner cases supported for
conditional_expressions. And that led me to thinking about the possible
implementation issues of these guys.

We never talked about implementation costs (at least at this meeting), like we
did when deferring generic type defaults. (And the concern there seems less
valid, since everything that can happen there can already happen in a generic
instantiation; there's nothing new like declaring a function in the middle of a
parameter list.)

We also never talked about the impact on readability. Our justification for @
was in part improved readability by elimination of duplication. But nothing
about this proposal really improves readability, since the nesting is very hard
to read. At best the readability is a wash, and if someone writes one of these
with a multiline result expression, the readability is much worse. Additionally,
since the types of the parameters are typically omitted, you usually still will
have to look at a separate declaration somewhere else to figure out what is
going on. That also harms readability.

We never really got an answer on what this is good for, either. The only thing I
heard was Tucker saying that every other language has added this. That seems
like a "lemming" excuse, but it doesn't actually answer what it is good for.
Given that every such function can be by definition written as an expression
function, this seems mainly to allow saving one line and a few names (of the
function and of the types of the parameters). That seems almost exclusively
aimed at making it easier to write code -- and that has never, ever been a goal
of Ada.

The use case that caused me to abstain is the quickie "<" or "=" operator in a
generic instance. But I had forgotten that Ada 2012 allows expression functions
everywhere, so nowadays you can always declare an expression function on the
line in front of an instance. That's good enough for me, and the readability is
not going to be impacted by that. In Ada 95, of course, you had to put the body
of this new function somewhere else. And if there is new functionality here, it
is essentially based on using the closure, an idea that I rather hope never
makes it into Ada.

As most of you remember, I strongly advocate the elimination of access type from
client interfaces. While that alone isn't a reason to reject something, it does
mean that I have no interest in making it easier to use something that I'd
prefer you don't use in the first place.

Ergo, once I think about this idea in detail, it's clear to me that the value of
the proposal is far less than the cost. Indeed, there almost is no value at all,
which means there is no amount of cost reduction which could make it worth it.

And honestly, I never really prepared an argument about the value of it since I
thought that no one really was supporting it anyway without some sort of closure
ability. So I wasn't prepared the other day. That's on me, sorry. (And now that
some closures are leaking into it, via quantified/declare identifiers, we're
already on the slippery slope to garbage collection hell.)

P.S. Richard, I can reargue this point now that I got the AI reopened for
technical issues. I was fully prepared to eat this complaint for all time, but
at least for the time being I don't have to.

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, December 13, 2018  9:06 PM

> Anybody object to "anonymous function"?

In favor of it.

(and against calling them lambdas, since lambda usually can do a lot more, e.g.,
currying and calling curried versions, returning composed lambdas and naming
them, etc.)

****************************************************************

From: Tucker Taft
Sent: Thursday, December 13, 2018  9:22 PM

...
> We never really got an answer on what this is good for, either. The only
> thing I heard was Tucker saying that every other language has added this.

Lambda expressions have been around since the earliest LISP days.  The value of
lambda expressions is that they ease the use of "higher-order" programming,
where you use various operators that apply functions to the elements of
composite data structures and then produce new sorts of results.  This is not
new.  What is new is that more and more programmers have become comfortable with
this sort of higher-order programming, and have found it is useful even in
languages that are not strictly "functional" programming languages.

We are working to attract a new generation of programmers to Ada.  These
programmers are growing up with higher-order programming as an important part of
how they solve complex problems.  But the need to create a local declare block
with a local function declaration and then pass in Blah'Access as part of this
sort of higher-order programming makes the whole process much heavier weight.
There is also a lot of redundancy in that process requiring producing a complete
formal part with parameter and result types that are copied directly from the
declaration of the access-to-function parameter of the higher-order function.
And finally there is the separation between the declaration of this local
"helper function" and the use of the helper function in the higher-order
operation.  So that now the "higher-order" operation becomes so heavyweight and
spread out that it becomes harder to understand what the programmer was trying
to do in the first place.

You are certainly right that the same thing can be accomplished by creating a
local declare block with a locally declared function (whose name is generally
just noise), and passing 'Access of it.  But the same thing could be said about
the container iterators, or protected objects instead of explicit lock/unlock,
or generalized references, etc.  The fact is that appropriate "syntactic sugar"
can change the game significantly, and make certain paradigms easy and natural
enough that more complex problems can be tackled.

...
> As most of you remember, I strongly advocate the elimination of access type
> from client interfaces. While that alone isn't a reason to reject something,
> it does mean that I have no interest in making it easier to use something
> that I'd prefer you don't use in the first place.

Anonymous access-to-subprogram types should really not be considered access
types at all.  They are really just a way to pass subprograms as parameters.
They have none of the issues that access-to-object types have, and really
shouldn't be grouped into the same bucket at all.

****************************************************************

From: Randy Brukardt
Sent: Thursday, December 13, 2018  11:36 PM

>>...
>>We never really got an answer on what this is good for, either. The
>>only thing I heard was Tucker saying that every other language has added this.

>Lambda expressions have been around since the earliest LISP days.  The
>value of lambda expressions is that they ease the use of "higher-order"
>programming, where you use various operators that apply functions to
>the elements of composite data structures and then produce new sorts of
results.

That is, spaghetti code. :-)

>This is not new.  What is new is that more and more programmers have become
>comfortable with this sort of higher-order programming, and have found it is
>useful even in languages that are not strictly "functional" programming
>languages.

I don't think this is new either.

>We are working to attract a new generation of programmers to Ada.
>These programmers are growing up with higher-order programming as an
>important part of how they solve complex problems.

Fine.

>But the need to create a local declare block with a local function
>declaration and then pass in Blah'Access as part of this sort of
>higher-order programming makes the whole process much heavier weight.

No, it makes it *readable*. You know, the number 1 priority of Ada programming
language design...

>There is also a lot of redundancy in that process requiring producing a
>complete formal part with parameter and result types that are copied
>directly from the declaration of the access-to-function parameter of
>the higher-order function.

Which again helps readability of the function, otherwise one has to look
elsewhere to understand what it means. There are very few places in Ada where
types are inferred, and adding new ones take a very high bar. (I'm somewhat
uncomfortable even doing for renames, I'd be much happier requiring the names to
be meaningful, but I know that's impossible because of compatibility.)

>And finally there is the separation between the declaration of this
>local "helper function" and the use of the helper function in the
>higher-order operation.

For a generic instantiation, they will be (or at least can be) directly next to
each other.

>So that now the "higher-order" operation becomes so heavyweight and
>spread out that it becomes harder to understand what the programmer was
>trying to do in the first place.

And putting it all in one place leads to LISP (in the bad way): Lots of
Irritating Stupid Parentheses. Figuring out what belongs to what becomes near
impossible. If the syntax of expressions was more readable, I would be less
concerned, but it is an unintelligable mess. It took a long time to write that
conformance example the last night, counting parens to figure out if it was
right. And you have the same thing with a compiler, since it can only guess at
which paren is missing or extra -- and those guesses only are right about half
of the time.

>You are certainly right that the same thing can be accomplished by
>creating a local declare block with a locally declared function whose
>name is generally just noise), and passing 'Access of it.

No declare block, because an instance already allows the declaration.
Anonymous access-to-subprogram are just pure evil, please avoid them.

In any case, this construct makes a call or instance itself many times harder to
read. The extra spacing and keywords helps that readability a lot, and certainly
makes it possible to figure out what the function and the call do individually.
That's necessary if you need to figure out an error -- otherwise you have a
write-only language.

>But the same thing could be said about the container iterators, or
>protected objects instead of explicit lock/unlock, or generalized
>references, etc.

Nope, each of them clearly makes the program *easier* to read. Some of them
arguably cover up too much dynamic semantics, but they surely make the program
*more* understandable. Nested constructs, OTOH, especially when not set off by
syntax, really have the opposite effect. This is a problem with all of the Ada
complex expression syntax, but at least those bring useful new capabilities
(especially to static expressions). Not so here.

>The fact is that appropriate "syntactic sugar" can change the game
>significantly, and make certain paradigms easy and natural enough that
>more complex problems can be tackled.

Sure, but this "sugar" is making the program completely unintelligable. Indeed,
that is a problem any time a subprogram is passed as a parameter, thus it is a
technique that ought to be used very sparingly. And the primary use I've had for
it (iterators) is better handled in Ada 2012 anyway.

>>...
>>As most of you remember, I strongly advocate the elimination of access type
>>from client interfaces. While that alone isn't a reason to reject something,
>>it does mean that I have no interest in making it easier to use
>>something that I'd prefer you don't use in the first place.

>Anonymous access-to-subprogram types should really not be considered access
>types at all.  They are really just a way to pass subprograms as parameters.
>They have none of the issues that access-to-object types have, and
>really shouldn't be grouped into the same bucket at all.

I agree, they should be avoided on their own merits. ;-)

They too severely harm readability of subprogram specifications. Nested
parameter lists get unreadable very quickly. I hadn't really realized how bad it
is until I was trying to write ACATS tests checking the various renaming null
exclusion rules. The subprograms passing anonymous access-to-functions are
complete messes, regardless of how you format them, as soon as they don't fit on
one line (and that was true for even relatively simple functions just using
Natural everywhere). Once you want to pass a function taking a functional
parameter to a third function, there is no hope (and that's pretty common in
higher-order programming).

Moreover, they are actively harmful in our goals of advancing correctness, since
they can't be given any contracts of their own -- so the writer of the
specification cannot communicate any requirements to the caller, and the caller
can't tell if they respected them. Trying to add those contracts to the
subprograms (as was once suggested by you) would make things even more
confusing, by mingling the contracts for the parameters and the base
subprograms.

In order to make these things readable, they *must* have some sort of named
type, which automatically would allow proper contracts and get rid of this
unreadable nesting. And if we did that, perhaps we could find a way to a
shorthand for making calls to these things. But it's really too late for this
round to engage in this sort of new feature invention.

In any case, multiplying the use of one unreadable feature by adding another
unreadable feature seems completely the wrong way to go for Ada. This whole area
requires more thought and a complete plan (for all sides of the question) and
not just a piece-meal approach.


In any case, my question was "what is this good for IN ADA". I don't care a lot
about adding some feature to attract "younger programmers" or "functional
programmers" or whatever kind of programmers you want, because I've heard that
line dozens of times in my many years of working in Ada. And I have yet to find
a single instance where adding something has had any real effect. People are
either attracted to Ada because of its readability and rigor and correctness, or
they aren't. And if they want to use it, they'll get around the occasional thing
that they find clunky. And otherwise, they'll use those clunky things as a
convenient excuse for not using Ada (when they never really would have used it
anyway).

And I know that a lot of people come to understand the virtues behind Ada's
declare everything explicitly philosophy, and it's emphasis on readability, and
so on. They might even appreciate that the stuff that they initially missed
isn't really as important as they thought.

So I view any feature for which the justification is "to attract more xxx
programmers to Ada" as having no justification at all. That is simply something
which only fools pursue.

Features have to make sense *for Ada*, otherwise they are a waste of effort. If
new features have some extra benefit of attracting new customers to Ada (as
contracts seem to have had), that's great, but we can't know that until after
the fact, so it should have no weight in whether or not to add features to Ada.

P.S. Note that generic formal type defaults is a similar sort of shorthand. But
that has a clear use in Ada: making ADTs easier to use and more readable for
clients (by eliminating the irrelevant from instantiations) - the idea behind
*every* shorthand that I've supported (and even some that I haven't).

****************************************************************

From: Jean-Pierre Rosen
Sent: Friday, December 14, 2018  12:27 AM

> Well, a natural implementation of this quantified expression puts Idx
> into a register temporary. External code, like this function here,
> would have no way to access such an Idx, as it would have no access to
> how the register temporary ends up getting mapped by the code
> generator (to a hardware register, to a spill location, or some combination).
>
> So the implementation would to recognize this special case and
> allocate a real memory location for it.

Disclaimer: it's been a very long time since I put my hands into a code
generator, but...

It seems to me that you first allocate variables to everything, and then the
optimizer decides to eliminate the variable for a register if possible. What you
describe doesn't seem to me to be a "natural implementation": there can be other
reasons that prevent the index from being a register.

****************************************************************

From: Randy Brukardt
Sent: Friday, December 14, 2018  2:05 AM

Sorry if I wasn't clear. A "register temporary" is a entity that is requested to
be put into a register if possible, or spilled to backing store if not. The code
generator ultimately decides what to do.

Ada has a lot of constructs that really cannot be implemented efficiently if the
intermediate parts have to be written to memory. For instance, think an others
clause in an array aggregate -- the working addresses need to stay in a register
if the code is to make any sense. (In most modern machines, performance is
roughly equivalent to the number of memory operations; that is a very good first
approximation.)

Additionally, code generators are written by different teams at different times,
have to deal with all of the oddities of the target architecture, and thus tend
to not be very similar. But every code generator has to deal with register
allocation, and the criteria is essentially the same for all targets -- get the
most used expressions into registers.

Since the loop index of a loop is always the most used expression for that loop,
it's automatic to put it into a register. The only reason that you wouldn't want
to do that would be if some optimization blocker like an accept statement or
exception handler appears in the loop -- but that can't happen for a quantified
expression. So why even bother with any other form of code generation?

I can't say what solution is given to other compilation systems, but our
solution was to pull as much as possible of the shared operations into the
front-end and optimizer, so that the code generator is essentially a peephole
operation - it only works on very local criteria. Thus, we essentially tell the
code generator what should be put into registers and what shouldn't. That saved
each code generator writing a complex register allocator, which would
approximate the existing common subexpression optimizer anyway. There's a
package of target-specific information to tailor that better to the target (that
was always there, as some code that appears simpler generates worse code in our
relatively simple code generators anyway; also some optimizations need to be
suppressed for some code generators [when the "code" generated is just the input
to another compiler, for instance, that's how we did the Unisys compiler.]).

In any case, implementation cost is always going to vary from compiler to
compiler. Arguments from it are always weak (which is one reason I'm getting
more and more upset over rejecting AI12-0205-1 solely for that reason).

****************************************************************

From: Edmond Schonberg
Sent: Friday, December 14, 2018  7:31 AM

...

> Moreover, they are actively harmful in our goals of advancing
> correctness, since they can't be given any contracts of their own --
> so the writer of the specification cannot communicate any requirements
> to the caller, and the caller can't tell if they respected them.
> Trying to add those contracts to the subprograms (as was once
> suggested by you) would make things even more confusing, by mingling
> the contracts for the parameters and the base subprograms.

This is probably the strongest argument against the introduction of anonymous
functions in the language. The Lots of Irritating Stupid Parentheses are not the
issue, but rather the fact that they make it much harder to describe the purpose
of a construct. If the anonymous function has a simple body it might as well be
written nearby as an expression function; if its body is complex the code
becomes impenetrable and this damages what seems to be the future of the
language, namely amenability to formal verification. Its introduction would be
additional complication not just for compiler writers (no big deal, they like
this sort of thing) but might just make programs harder to analyze by tools such
as SPARK, make compilers harder to certify, and lead developers to define
subsets of the language that exclude anonymous functions! Not clear to me that
the gains outweigh these problems.

****************************************************************

From: Tucker Taft
Sent: Friday, December 14, 2018  8:26 AM

Readability is best assessed by examples.  Presume we have a search function
that takes a predicate:

   function Search
      (C : Container;
       Predicate : access function (Elem : Element) return Boolean)
   return Element;

We would like to use it to search for, say, any element in a container that has
a value >= Min_Value:

  Put_Line ("Found element with value >= Min_Value: " &  Elem_Image
      (Search (My_Container,
                    Predicate => (function (E) return Value(E) >= Min_Value))));

vs.

   declare
        function Predicate (E : Element) return Boolean is (Value(E) >= Min_Value);
   begin
        Put_Line ("Found element with value >= Min_Value: " &  Elem_Image
           (Search (My_Container, Predicate => Predicate'Access)));
   end;

Seems like a lot of "noise" in that second version, without any additional
"signal."

****************************************************************

From: John Barnes
Sent: Friday, December 14, 2018  11:38 AM

I would vote for lambda expression. It was widespread in the course I went to at
Oxford in 1962.

It wouldn't be a whole chapter just a section but a majestic title.

****************************************************************

From: Jeff Cousins
Sent: Friday, December 14, 2018  1:41 PM

A shame I had to miss this part of the recent meeting.

Anonymous function is certainly an improvement in the name over function
expression, though Im afraid that abstain would be as positive as I could be
about the whole idea.

****************************************************************

From: Randy Brukardt
Sent: Friday, December 14, 2018  3:48 PM

> Seems like a lot of "noise" in that second version, without any
> additional "signal."

I'd actually agree. But the problem here is this is the absolute best case for
this feature:
  (1) There's no need for comments in the function;
  (2) The result expression of the anonymous function fits in a handful of
      characters;
  (3) There's no need for contracts on the function (for which predicate
      functions are pretty much the sole example);
  (4) There's only a single parameter, so you can get away with calling it "E".
  (5) Your using it in a subprogram call rather than the more typical generic
      instantiation, so you need the "noise" of the declare block.

Typical Ada programming style would suggest that (1) and (4) should be rare,
(3) is rare as I noted, and (2) isn't that common either. (5) depends on your
programming style, but I'd expect that much of the time there is a nearby
declarative part that you could use instead.

As soon as any of these aren't true, the readability plummets.

Try this example with a more typical function with two parameters and a 3-line
conditional expression. You can't even read the initial function declaration,
much less the call. (A quick look to find the type of the function result has a
50-50 chance of turning up the wrong one.) If we're actually going to expect
people to use this feature extensively, even the existing stuff needs an
overhaul.

Aside: When I read this message on my phone this morning, the word wrapping made
the code into a mess; even the function declaration got split into multiple
parts. I see the Outlook quoting system did the same above. This just shows what
happens to readability when the lines get longer.

I think I started out by saying that the readability is at best a wash, and this
is that case -- you've gained by eliminating the name and lost due to the
nesting. And if you have trouble understanding passing functions in the first
place (like me), the nesting makes it worse (the presence of 'Access cues me to
the fact that something unusual is going on).

****************************************************************

From: Tucker Taft
Sent: Sunday, December 16, 2018  9:20 AM

>Typical Ada programming style would suggest that (1) and (4) should be rare,

I think you are missing the point -- typical Ada style can be too heavyweight
for the common straightforward cases where functional programming streamlines
things.  Functional programming in my experience is built on functions that
capture variability that might otherwise need to be captured in multiple
parameters and complex interfaces.  Rather than passing in lots of parameters to
control how a data structure should be processed, you pass in one or two
functions with simple interfaces (i.e. one or two parameters), which incorporate
within their body all the variability that is needed.

For example, imagine a database management system, which wants to provide an
ability to select a bunch of records, and then combine them in some useful way.
This implies a selection function, and a combination function.  The selection
function would take in a record and return True or False (i.e., filtering), and
the combination function would take in a record and a combination value and
return the new combination value (i.e., reduction).  What you are really doing
is passing in "parameterized expressions," which can be as simple as:

    (rec) such that (rec.value >= N)
and:
    (accum, rec) producing (accum + rec.value ** 2)

Hence, this maps very nicely to something like:

    Large_Val_Sum_Of_Squares := Database_Query
       (My_Database,
        Select => (function (Rec) return (Rec.Value >= N),
        Combine => (function (Accum, Rec) return Accum + Rec.Value ** 2));

Finding or creating an appropriate declare block to declare these expressions as
separate functions, potentially somewhat distant from the invocation of the
database operation, can defeat the purpose of having this sort of database
abstraction.

Of course if you have something significantly more complicated, there is no
requirement to use these short-hands.  That is a major advantage of "syntactic
sugar" in my view.  The short-hand is not introducing some fundamentally new
capability, but rather making the existing functionality more usable and
readable for the frequent simple case.  The underlying capability is always
available for those who find the short-hand less readable in some complex case,
while the short-hand is available when it makes the functionality of the
relatively simple case more readable.

****************************************************************

From: Arnaud Charlet
Sent: Sunday, December 16, 2018  10:00 AM

> I think you are missing the point -- typical Ada style can be too
> heavyweight for the common straightforward cases where functional
> programming streamlines things.  Functional programming in my
> experience is built on

Fully agreed. Trying to argue on style and on what people would do today in Ada
isn't really appropriate for new features. Best is to look at how people use
similar features in languages where these features already exist.

And yes, there are many cases where these shorthands make a lot of sense for
relatively small expressions and this is where people will typically use them.

Arguing that some people will misused this feature with more complex cases is
missing the usefulness of the feature: yes, any feature can be misused by
people, that's what style  guides and coding standards are for, and this isn't
what a language standard should be about (anymore anyway, we're well past that
point at this stage).

In addition:

> I'd actually agree. But the problem here is this is the absolute best
> case for this feature:
>  (1) There's no need for comments in the function;

That's typically the case for this kind of shorthand.

>  (2) The result expression of the anonymous function fits in a handful
> of characters;

Same.

>  (3) There's no need for contracts on the function (for which
> predicate functions are pretty much the sole example);

Again, this kind of simple function is precisely where people would *not* put
contracts on anyway. People already do not put contracts on similar simple
functions today, this is our experience with SPARK.

>  (4) There's only a single parameter, so you can get away with calling
> it "E".

One or a few parameters is the typical use case for this feature.

> Typical Ada programming style would suggest that (1) and (4) should be
> rare,

Not in our experience these days.

****************************************************************

From: Randy Brukardt
Sent: Monday, December 17, 2018  4:54 PM

..
> > Typical Ada programming style would suggest that (1) and
> > (4) should be rare,
>
> Not in our experience these days.

Really? You're saying that code rarely needs comments or good naming to be
understandable?

My personal experience is that when maintaining old code, even if I wrote it
originally (but many years previous), many things that I considered "obvious"
and not needing comments then are very difficult to understand now. I can only
imagine how much harder it is when it is necessary to maintain someone else's
code.

The only code that doesn't need good comments is throwaway code (code that is
literally not going to be used again). I'd expect that there is very little
throwaway code written in Ada (and even when I've written such code, I've often
went back to it in the future to repurpose it). In any case, throwaway code
doesn't need readability, so it's clearly not a focus of Ada.

And the only real advantage of this particular proposal is the avoidance of the
need to pick a good name for the function. If picking good names don't really
matter in your code, then that is not a problem and there is even less value to
this proposal than it appears.

****************************************************************

From: Tucker Taft
Sent: Monday, December 17, 2018  5:30 PM

> Really? You're saying that code rarely needs comments or good naming
> to be understandable?

Again, the point is that the individual "parameterized expression" isn't the
place where you would necessarily want to put the comment.  Instead, on the
enclosing call to, for example, the Database_Query operation, you would put a
comment about what you are trying to accomplish overall.

And as usual, if you really want to comment the parameterized expression, feel
free!

****************************************************************

From: Arnuad Charlet
Sent: Tuesday, December 18, 2018   1:49 AM

>>> Typical Ada programming style would suggest that (1) and
>>> (4) should be rare,
>>
>> Not in our experience these days.
>
> Really?

Yes

> You're? saying that code rarely needs comments or good naming to be
> understandable?

No, you read my comment out of context. In the context of these small helper
functions (such as expression functions in Ada 2012), these are much more common
since the code is in effect acting as a formal specification.

> My personal experience is that when maintaining old code, even if I
> wrote it originally (but many years previous), many things that I
> considered "obvious" and not needing comments then are very difficult
> to understand now. I can only imagine how much harder it is when it is
> necessary to maintain someone else's code.

I doubt these include Ada 2012 expression functions, hence my  these days 
comment.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, December 18, 2018  2:24 AM

...
> > You're? saying that code rarely needs comments or good naming to be
> > understandable?
>
> No, you read my comment out of context. In the context of these small
> helper functions (such as expression functions in Ada 2012), these are
> much more common since the code is in effect acting as a formal
> specification.
>
> > My personal experience is that when maintaining old code, even if I
> > wrote it originally (but many years previous), many things that I
> > considered "obvious" and not needing comments then are very
> > difficult to understand now. I can only imagine how much harder it
> > is when it is necessary to maintain someone else's code.
>
> I doubt these include Ada 2012 expression functions, hence my < these
> days > comment.

Really? Replacing three keywords with parens somehow changes the need to
document??

Whatever you are trying to say, it doesn't have anything to do with the form of
the declaration!

If you have a function, you have to explain what it does and why you're using
the formula given in it. The form of the declaration has nothing to do with
that.

If you can't explain what a function is for, then it shouldn't be a function at
all; find some other way to decompose the program.

P.S. I've written plenty of expression functions, including tonight. Lots of my
existing code would use them, to, if my compiler supported them.

****************************************************************

From: Gary Dismukes
Sent: Tuesday, December 18, 2018  1:43 AM

Here's a comment/question about one aspect of the proposal (see below).

> !wording
>
> ...
>
>   In a context where there is an expected type rather than an expected
>   profile for an anonymous_function, the expected type shall be a single
>   anonymous access-to-function type, and the profile of this type is considered
>   the expected profile for the anonymous_function.  The result type of

In the first sentence above, why is the expected type being limited to an
*anonymous* access-to-function type?  Don't we intend to allow this feature for
use with formals of named access-to-function types as well, and if not, why not?
BTW, one of the examples involves a named type.

> !discussion
>
> ...
>
> We limit this to cases of anonymous access-to-subprogram types used as
> function parameters.  Other cases, like access discriminants and
> stand-alone access objects seemed like more trouble that they are
> worth, since those generally occur in contexts where declaring a local
> subprogram is not a burden.

This !discussion paragraph also seems to indicate that the feature is limited to
cases where the type is anonymous.  I don't see why it would be limited that
way, is this really intended?  (And that should presumably say
"access-to-function types".)

Also, it says "used as function parameters", but surely that should be "used as
subprogram parameters", since we also allow them to be passed as parameters in
procedure calls.

> !example
>
>     --  Replace control chars with '?'
>     Ada.Strings.Fixed.Translate
>       (Str, (function (C) return (if C < ' ' then '?' else C)));
>

The second parameter of Translate is a named access-to-function type (type
Character_Mapping_Function).

****************************************************************

From: Tucker Taft
Sent: Tuesday, December 18, 2018  12:27 AM

>>  In a context where there is an expected type rather than an expected
>> profile for an anonymous_function, the expected type shall be a
>> single  anonymous access-to-function type, and the profile of this
>> type is considered  the expected profile for the anonymous_function.
>> The result type of
>
> In the first sentence above, why is the expected type being limited to
> an *anonymous* access-to-function type?  Don't we intend to allow this
> feature for use with formals of named access-to-function types as
> well, and if not, why not?

Because a named access type has an accessibility level, and these anonymous
functions are declared more locally than any named access type.

>  BTW, one of the examples involves a named type.

Good point, the Ada.Strings.Fixed.Translate example should be replaced, perhaps
with one of the Database_Query examples mentioned in this (endless) e-mail
chain.
...

> This !discussion paragraph also seems to indicate that the feature is
> limited to cases where the type is anonymous.  I don't see why it
> would be limited that way, is this really intended?  (And that should
> presumably say "access-to-function types".)

Yes, as indicated above, accessibility rules require that the formal parameter
be of an anonymous access-to-function type.

>
> Also, it says "used as function parameters", but surely that should be
> "used as subprogram parameters", since we also allow them to be passed
> as parameters in procedure calls.

Yes, good point.  Should say subprogram parameters.

>>
>> !example
>>
>>    --  Replace control chars with '?'
>>    Ada.Strings.Fixed.Translate
>>      (Str, (function (C) return (if C < ' ' then '?' else C)));
>>
>
> The second parameter of Translate is a named access-to-function type
> (type Character_Mapping_Function).

Agreed -- this example should be replaced.

****************************************************************

From: Gary Dismukes
Sent: Tuesday, December 18, 2018  2:30 PM

> Because a named access type has an accessibility level, and these anonymous
> functions are declared more locally than any named access type.

Ah right, I should have thought of that. :-)

BTW, the !summary should perhaps be changed to say "that has an {anonymous}
access-to-function parameter" (also first paragraph of !proposal).  And should
the part that says ", or other contexts where the expected type is an
access-to-function type," be removed, since these are basically only allowed for
subprogram calls (according to the legality rule that you added), or are there
actually other legal contexts involving expected types that I'm missing?

****************************************************************

From: Tucker Taft
Sent: Tuesday, December 18, 2018  2:58 PM

> BTW, the !summary should perhaps be changed to say "that has an
> {anonymous} access-to-function parameter" (also first paragraph of
> !proposal).  And should the part that says ", or other contexts where
> the expected type is an access-to-function type," be removed, since
> these are basically only allowed for subprogram calls (according to
> the legality rule that you added),

All good suggestions.

> or are
> there actually other legal contexts involving expected types that I'm missing?

We simplified by limiting this to access parameter cases, since discriminants
and stand-alone access objects of an anonymous type just hurt too much to think
about. ;-)

****************************************************************

From: Steve Baird
Sent: Tuesday, December 18, 2018  8:13 PM

The proposed wording generally looks good to me.
I've got a couple of questions.

Is it clear from the proposed wording that the only contexts in which an
anonymous function can occur are either
    a) in a context where an access-to-function type is the expected
       type; or
    b) as an actual in an instance corresponding to a formal subprogram ?

We have the introductory wording
>   Anonymous functions provide a way to define a function at a point
>   where an access-to-function type is the expected type, or in a generic
>   instantiation as an actual parameter corresponding to a formal subprogram
>   parameter.

but that's not usually how we do this kind of thing (I'm not suggesting changing
that wording - only augmenting it elsewhere).

I think we need a clearer rule stating that these guys cannot be renamed, cannot
occur in an aspect specification in a context where a name denoting a function
is expected, etc.

I assume we want to prevent
     for T'Input use (<some anonymous function>); or
    function F (X : T) return T renames (<some anonymous function>); .

====

We've got

>   An anonymous_function used in a context where there is an expected
>   type is equivalent to an expression_function_declaration (see
>   6.8) declared within the innermost declarative region with the
>   anonymous_function replaced by an Access
>   attribute_reference of this locally defined function

and similarly for the actual-subprogram-of-an-instance case.

Do we want a TBH note clarifying that it wouldn't always be possible for users
to declare this "equivalent" expression function at the source level (e.g., if
it occurs within a quantified expression or an iterated component association)?

Maybe this is unnecessary, but intuitively the above rule seems to suggest that
this is a more of a "syntactic sugar" construct that it really is.

====

Do we need to update the accessibility rules to handle the following construct?

The proposed "innermost declarative region" wording does what we want with
respect to visibility, but does it correctly reject a bad construct like

  procedure Test is
     type Rec (Discrim : access function return Integer := null) is
        limited null record;

     type Vec is array (Positive range <>) of Rec;

     procedure Consume_Vec (Arg : Vec) is null;
   begin
    Consume_Vec
      (Arg => Vec'(for Idx in 1 .. 10 =>
                     Rec'(Discrim => (function return Idx))));
   end;

I think there may be a problem here because the definition of "master" is too
coarse to prevent what this example is trying to do.

***************************************************************

From: Tucker Taft
Sent: Tuesday, December 18, 2018  8:52 PM

> We have the introductory wording
>>  Anonymous functions provide a way to define a function at a point
>> where an access-to-function type is the expected type, or in a
>> generic  instantiation as an actual parameter corresponding to a
>> formal subprogram  parameter.
>
> but that's not usually how we do this kind of thing (I'm not
> suggesting changing that wording - only augmenting it elsewhere).

I agree.

> I think we need a clearer rule stating that these guys cannot be
> renamed, cannot occur in an aspect specification in a context where a
> name denoting a function is expected, etc.
>
> I assume we want to prevent
>    for T'Input use (<some anonymous function>); or
>   function F (X : T) return T renames (<some anonymous function>);

I suspect these are harmless, but I agree we might as well restrict the context so they can only be used as generic formal function actuals, generic formal function defaults, callable-parameters, and callable defaults.

> .
>
> ====
>
> We've got
>
>>  An anonymous_function used in a context where there is an expected
>> type is equivalent to an expression_function_declaration (see
>>  6.8) declared within the innermost declarative region with the
>> anonymous_function replaced by an Access  attribute_reference of this
>> locally defined function
>
> and similarly for the actual-subprogram-of-an-instance case.
>
> Do we want a TBH note clarifying that it wouldn't always be possible
> for users to declare this "equivalent" expression function at the
> source level (e.g., if it occurs within a quantified expression or an
> iterated component association)?

I believe there is already such a TBH, a little further down.

> Maybe this is unnecessary, but intuitively the above rule seems to
> suggest that this is a more of a "syntactic sugar" construct that it
> really is.
>
> ====
>
> Do we need to update the accessibility rules to handle the following
> construct?
>
> The proposed "innermost declarative region" wording does what we want
> with respect to visibility, but does it correctly reject a bad
> construct like
>
> procedure Test is
>    type Rec (Discrim : access function return Integer := null) is
>       limited null record;
>
>    type Vec is array (Positive range <>) of Rec;
>
>    procedure Consume_Vec (Arg : Vec) is null;  begin
>   Consume_Vec
>     (Arg => Vec'(for Idx in 1 .. 10 =>
>                    Rec'(Discrim => (function return Idx))));  end;
>
> I think there may be a problem here because the definition of "master"
> is too coarse to prevent what this example is trying to do.

We specifically do *not* want to allow these for access discriminants, to avoid
getting into the 3.10.2 heart-of-darkness territory.  That is why they are only
permitted as parameters or defaults to a subprogram where the formal is of an
anonymous access-to-function type.

****************************************************************

From: Tucker Taft
Sent: Tuesday, December 18, 2018  9:27 PM

>I believe there is already such a TBH, a little further down.

I had already suggested such a TBH in this long e-mail chain, but it got lost
when I updated the AI.  Here is what I had proposed:

{AARM To Be Honest: Depending on the nature of the innermost enclosing
 declarative region, this equivalence might violate the normal syntax rules
 which would not permit such an expression_function_declaration in such a
 region.}

****************************************************************

From: Tucker Taft
Sent: Tuesday, December 18, 2018  9:50 PM

Here is a version that incorporates comments from Gary, Steve, and Bob. [This is
version /07 of the AI - Editor.]

****************************************************************

From: Steve Baird
Sent: Wednesday, December 19, 2018  11:31 AM

> I agree we might as well restrict the context so they can only be used as
> generic formal function actuals, generic formal function defaults,
> callable-parameters, and callable defaults.
>> .

...

> We specifically do *not* want to allow these for access discriminants, to
> avoid getting into the 3.10.2 heart-of-darkness territory.  That is why they
> are only permitted as parameters or defaults to a subprogram where the formal
> is of an anonymous access-to-function type.

I agree with all of the above (and I agree that this would address my
accessibility concerns), but I don't understand how the version 7 wording you
proposed accomplishes this.

What prevents, for example, using an anonymous function as an
access-to-subprogram discriminant value?

I suspect I am missing something.

****************************************************************

From: Tucker Taft
Sent: Wednesday, December 19, 2018  11:35 AM

> I agree with all of the above (and I agree that this would address my
> accessibility concerns), but I don't understand how the version 7
> wording you proposed accomplishes this.
>
> What prevents, for example, using an anonymous function as an
> access-to-subprogram discriminant value?

The legality rules say:

 When used in a context where there is an expected type, the  anonymous_function
 shall be an actual parameter in a call, or a  parameter default for a callable
 entity.  When used in a context  where there is only an expected profile, the
 anonymous_function  shall be a generic actual parameter in a
 generic_instantiation for a  formal subprogram parameter, or as the
 subprogram_default for such a formal  subprogram parameter.

Doesn't this make it clear that these cannot be used for access discriminants?
>
> I suspect I am missing something.

Perhaps the Legality Rules could be restated somehow.  But they seem pretty
clear to me.

****************************************************************

From: Steve Baird
Sent: Wednesday, December 19, 2018  11:41 AM

> Doesn't this make it clear that these cannot be used for access discriminants?

Yes, I just managed to confuse myself.

The wording is fine,

Sorry about the noise.

****************************************************************

From: Gary Dismukes
Sent: Wednesday, December 19, 2018  1:57 AM

> ...
>
> !summary
>
> Provide an ability to construct a local anonymous function at the
> point of a call on a subprogram that has an access-to-function
> parameter, or in an instantiation with a formal subprogram parameter.

I would like the !summary to say "... a call on a subprogram that has an
{anonymous} access-to-function parameter, ...".  I guess you forgot to make that
change. :)

****************************************************************

From: Tucker Taft
Sent: Wednesday, December 19, 2018  1:57 AM

Oops!  Consider the change made... ;-)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, January 9, 2019  12:03 AM

> Here is a version that incorporates comments from Gary, Steve, and 
> Bob.

You used an older version of this as the basis, so you put back various 
errors that I had corrected.

I also had get rid of 22 extra spaces after periods. :-)

---

I never saw a definitive answer to my original question about conformance of 
anonymous function, or for that matter for the declaration in the expression 
of the body.

The original example was:

   package Pack is
      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural;
   end Pack;

   package body Pack is
      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural is ...
   end Pack;

   with Pack;
   procedure Main is
      V : Natural := Pack.Ugh;
   begin
      Put (V'Image);
   end Main;

There are two issues here. 

The lesser issue is that each of these functions are separate declarations, 
so there has to be a (dead) declaration and body for the second. And the 
compiler clearly will have to do most of the compilation steps on that 
second one, since it could have different resolution than the first. So 
there has to be yet another special case in the compiler (unless it has 
good dead subprogram elimination and its OK to waste time compiling 
something that will never be used.

The primary issue, however is how this is handled for conformance.

Steve points to 6.3.1(21/4), which says:

each direct_name, character_literal, and selector_name that is not part of the 
prefix of an expanded name in one denotes the same declaration as the 
corresponding direct_name, character_literal, or selector_name in the other, 
or they denote corresponding declarations occurring within the two 
expressions; and 

It seems this works for the anonymous function itself, but I don't know if it 
works for the (A). This is described in terms of the profile of the outer 
declaration rather than being a declaration of its own, and while I suppose 
we could just handwave it (it has to be some sort of declaration if it is 
making a name visible), we should at least make that handwaving explicit with 
an AARM note.

Note that depending on this rule means that the ids in the profiles don't have 
to be the same, they just have to denote the same parameter:

   package Pack is
      function Ugh (P : Natural := Foo ((function (A) return A*2), 2)) return Natural;
   end Pack;

   package body Pack is
      function Ugh (P : Natural := Foo ((function (B) return B*2), 2)) return Natural is ...
   end Pack;

6.3.1(20.1/4) is supposed to prevent that:
   corresponding defining_identifiers occurring within the two expressions are
   the same; and

but it doesn't apply here as there are no defining_identifiers in the syntax 
of an anonymous function.

Not sure if something ought to be changed to eliminate this possibility, but 
at minimum there should be some sort of AARM note about conformance of 
parameters of anonymous functions and probably some mention of conformance in 
the !discussion.

****************************************************************

Questions? Ask the ACAA Technical Agent