Version 1.7 of ai12s/ai12-0075-1.txt

Unformatted version of ai12s/ai12-0075-1.txt version 1.7
Other versions for file ai12s/ai12-0075-1.txt

!standard 4.9(6)          18-01-05 AI12-0075-1/05
!standard 4.9(18)
!class Amendment 13-06-09
!status work item 13-06-09
!status received 13-05-07
!priority Medium
!difficulty Medium
!subject Static expression functions
!summary
An expression function can be static in appropriate circumstances.
!problem
It should be possible to use an expression function in a static expression. This would allow greater abstraction for static expressions, which sometimes can get quite large.
!proposal
(See summary.)
!wording
Add to the definition of static function (i.e. insert as the penultimate item of the 4.9 (19-22) list):
- a static expression function (see 6.8)
Add at the and of the 4.9 "Legality Rules" section:
AARM Discussion: The preceding "statically unevaluated" rule allows
X : constant := (if True then 37 else (1 / 0))
but does not allow
function If_Then_Else (Flag : Boolean; X, Y : Integer) is (if Flag then X else Y) with Static; -- see 6.8 X : constant := If_Then_Else (True, 37, 1 / 0);
because evaluation of a function call includes evaluation of all of its actual parameters.
Introduce a "Static Semantics" section for 6.8 immediately before the "Legality Rules" section, containing:
A "potentially static expression" is defined in the same way as a static expression except that
- a name denoting a formal parameter of an expression function
is a potentially static expression; and
- each use of "static expression" in
the definition of "static expression" is replaced with a corresponding use of "potentially static expression" in the definition of "potentially static expression".
AARM Discussion: These uses occur in the definition of "static expression" in the cases of function calls, type conversions, qualified expressions, membership tests, short circuit control forms, conditional expressions, and parenthesized expressions.
A "potentially static expression function" is defined to be an expression function
- whose expression is a potentially static expression; and - which contains no calls to itself; and - each of whose parameters (if any) is of mode IN and is of a static subtype; and - whose result subtype is a static subtype; and - to which no precondition or postcondition expression applies; and - which is not type invariant enforcing for any type (see 7.3.2); and - which is not a completion.
The following language-defined representation aspect may be specified for a potentially static expression function.
Static - The type of aspect Static is Boolean.
A "static expression function" is defined to be an expression function whose Static aspect is True. In addition, an inherited function is defined to be a static expression function if the corresponding primitive function of the parent or progenitor type is a static expression function. [A static expression function is a static function; see 4.9].
In 7.3.2, add the following at the end of the Static semantics section.
If one or more invariant expressions apply to a nonabstract type T, then a subprogram or entry is said to be "type invariant enforcing" for T if
- it is the Read or Input stream-oriented attribute of the type T; or - it is declared within the immediate scope of T (or by an instance of a
generic unit, and the generic is declared within the immediate scope of type T), and either:
* has a result with a part of type T; or
* has one or more *out* or *in out* parameters with a part of type T; or
* has an access-to-object parameter or result whose designated type has a part of type T; or
* is a procedure or entry that has an *in* parameter with a part of type T.
- and either:
* T is a private type or a private extension and the subprogram or entry is visible outside the immediate scope of type T or overrides an inherited operation that is visible outside the immediate scope of T; or
* T is a record extension, and the subprogram or entry is a primitive operation visible outside the immediate scope of type T or overrides an inherited operation that is visible outside the immediate scope of T.
Each such part of type T is said to be "subject to an invariant check" for T.
In the Dynamic Semantics section, replace 7.3.2(15/4-20/5) with
An invariant check is checked upon successful return from a call on any subprogram or entry which is type invariant enforcing for T. The check is performed on each part of type T which is subject to an invariant check for T.
!discussion
The stuff in 7.3.2 (type invariants) is all intended to be semantics-preserving. The only goal of this rearrangement is to define the term "type invariant enforcing" so that we can say that an expression function which is "type invariant enforcing" for some type T is not a potentially static expression function. And, of course, the term itself is subject to discussion - we might choose a different term.
This version incorporates feedback from the last two meetings so that
a) in order for an expression function to be a static function, you
have to explicitly ask for it by specifying the Static aspect (a new Boolean aspect).
b) an expression function which is a completion is never a static
function. No view-specific stuff where sometimes it is and sometimes it isn't, depending on whether the completion is visible.
c) an expression function which is subject to a type invariant is
never a static function.
!example
!ASIS
** ASIS queries needed **
!ACATS test
ACATS B-Tests and C-Tests.
!appendix

From: Jean-Pierre Rosen
Sent: Tuesday, May  7, 2013  7:28 AM

First asking, in case it has been discussed before...

Wouldn't it be possible to make some expression functions static?

Apparently, all that is needed is to add "formal parameters of an expression
function" to the list of static things in 4.9. (Of course, the actual
parameters of the call would have to be static, but that's already covered by
4.9(6))

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

From: Randy Brukardt
Sent: Tuesday, May  7, 2013  6:24 PM

> First asking, in case it has been discussed before...
>
> Wouldn't it be possible to make some expression functions static?

This was mentioned as a possible extension in the original AI. The !discussion
section of AI05-0177-1 says:

One could imagine allowing these functions (when visible) to be used in static
expressions if the inlined expression would be static. This would definitely
allow abstracting expressions that currently are written as a giant single
expression because they need to be static. That's something you cannot do now.
We didn't add this to proposal in order to keep the proposal simple.

There's a bit of discussion of this in the e-mail, but nothing very interesting.
I thought we also discussed it briefly at a meeting, but I didn't find anything
in the October 2010 minutes when this was mainly discussed.

> Apparently, all that is needed is to add "formal parameters of an
> expression function" to the list of static things in 4.9. (Of course,
> the actual parameters of the call would have to be static, but that's
> already covered by  4.9(6))

I think it would be necessary for the fact that it is an expression function to
be visible at the point of use. That would limit the value of this as it would
prevent expression functions used as completions from participating. If we were
willing to break privacy, we could allow expression functions used as completion
in the private part, but that's probably a bad idea.

Perhaps a better idea would be to have an aspect Static_Possible that could be
applied to a subprogram declaration. The completion then would have to be an
expression function that can be static.

Also, I think there would have to be rule that for such a function the
expression of it is static if one considers the parameters static. (And since
not all types can be static, if there are any problems that aren't of either
scalar or string types, then those parameters would be non-static.) And we'd
need some sort of rule to deal with recursion (that's something we don't
currently have to deal with in static expressions), unless we're willing to have
compilers crash in such circumstances. (Running out of memory is hard to check
for accurately, and it's often impossible to recover.)

Anyway, this is a non-trivial idea. No problem with adding it as a possible
Amendment, but it isn't going to magically appear as a Binding Interpretation in
Ada 2012 (we already rejected that idea initially).

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

From: Robert Dewar
Sent: Tuesday, May  7, 2013  6:38 PM

> Anyway, this is a non-trivial idea. No problem with adding it as a
> possible Amendment, but it isn't going to magically appear as a
> Binding Interpretation in Ada 2012 (we already rejected that idea initially).

Maybe we should try implementing Randy's pragma first, and see if there are
unforseen difficulties. With that pragma, we don't even have to limit it to
expression functions!

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

From: Steve Baird
Sent: Wednesday, May  8, 2013  4:18 PM

> Anyway, this is a non-trivial idea. No problem with adding it as a
> possible Amendment, but it isn't going to magically appear as a
> Binding Interpretation in Ada 2012 (we already rejected that idea initially).

You got that right.

We'd have to be careful not to ignore the subtypes of the formal parameters.

When we "plug in" the arguments to see if the resulting expression is static, I
think we'd need to treat the plugged-in value like a qualified expression,
qualified by the subtype of the formal.

There is also the question of ignored formal parameters.

A particularly pathological example:

    package Pkg is
        type T is private with Invariant => Is_Even (T);

        function Is_Even (X : T) return Boolean;

        function Zoofle (X : in out T; Y, Z : Integer) return Integer
         is (Y + Z) with Static_Possible;

    private
        type T is new Integer;

        function Is_Even (X : T) return Boolean is (X mod 2 = 0);

        Invalid : T := 3;

        Three : constant Integer := Zoofle (Invalid, 1, 2); -- static?
    end Pkg;

We'd probably deal with this particular case by just requiring formal parameters
to be of mode In, but the point is that such a rule would need to be stated.

I agree with Randy; this is not a one-liner.

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

From: Robert Dewar
Sent: Wednesday, May  8, 2013  4:31 PM

> We'd probably deal with this particular case by just requiring formal
> parameters to be of mode In, but the point is that such a rule would
> need to be stated.

To me that's an OBVIOUS restriction for a static function

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

From: Steve Baird
Sent: Wednesday, May  8, 2013  5:33 PM

Interactions with short circuit evaluation, for example, might be less obvious.

     Flag_V1 : constant Boolean := True or else (1 / 0) = 123;

is static, but presumably this version

     function Or_Else (C1, C2 : Boolean) return Boolean is
         (C1 or else C2) with Static_Possible;

     Flag_V2 : constant Boolean := Or_Else (True, (1 / 0) = 123);

would not be static.

My only real point is to agree with Randy: this is not a one-liner, if only
because these "OBVIOUS" restrictions would need to be stated.

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

From: Robert Dewar
Sent: Wednesday, May  8, 2013  5:56 PM

>       Flag_V2 : constant Boolean := Or_Else (True, (1 / 0) = 123);
>
> would not be static.

I would not allow anything like this most certainly. All arguments to a function
have to be static. Again that seems like an obvious restriction. (1 / 0) = 123
is not a static expression!

> My only real point is to agree with Randy: this is not a one-liner, if
> only because these "OBVIOUS" restrictions would need to be stated.

The proper approach would be to make the restrictions as tight as possible,
rather than getting into the tempting mode of making them as universal as
possible.

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

From: Steve Baird
Sent: Tuesday, August 25, 2015  4:06 PM

Here is a first cut at an AI allowing calls to expression functions to occur
in static expressions. This is part of my Madrid homework. [This was version
/04 of the AI - Editor.]

Many thanks to Randy for his helpful comments (but please do not take this to
mean that Randy agrees with anything in this proposal).

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

From: Tucker Taft
Sent: Monday, September 14, 2015  3:52 PM

Looks good.  I agree we probably don't want an attribute.

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

From: Steve Baird
Sent: Saturday, September 17, 2015 11:20 PM

!wording differences from previous version are highlighted. [This is
version /04 of the AI - Editor.]

The idea with this change is that a call to an expression function with static
arguments which fails a check (during its compile time evaluation) is simply
not a static expression, as opposed to being illegal.

This addresses the compatibility issue that Randy raised. [But it doesn't
address the original compatibility issue that Steve himself raised - Editor.]

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

From: Steve Baird
Sent: Thursday, October  5, 2017  2:55 PM

It seems clear that compatibility issues are a major concern associated with
this proposal.

We don't want examples which were previously legal to start running afoul of
the "no check failures in a static expression" rule.

Bob suggested one solution to this problem: an expression which fails the
"no check failures" test becomes non-static, as opposed to illegal.

But the consensus in Vienna (I am told) was that we also don't want to start
allowing constructs which were previously illegal.

There is a solution which satisfies both constraints, although I am not
claiming that it is elegant: we relax the legality rules as per Bob's proposal
but only in the case of a static expression that includes a call to an
expression function. Such an expression could never currently be static, so
this relaxation would not cause us to accept something that was previously
rejected.

So we would continue to disallow

     N : constant := 0;
   begin
     if N /= 0 then
        X := 10 / N;
     end if;

but we would also continue to allow

    N : constant := 0;
    function Ratio (X : Integer) return Integer is (X / N);
  begin
    if N /= 0 then
      X := Ratio (10);
    end if;

====

I was tasked with assessing the compatibility impact of an earlier version of
this proposal, trying to somehow figure out how often situations like

      procedure Foo is
       function Inc (X : integer) return Integer is (X + 1);
       subtype S is Integer range 0 .. Inc (3);
       Y : S := ... ;
    begin
       -- if S is a static subtype then this case stmt is illegal
       case Y is
          when  0 .. 33 => ...;
          when  44 .. 55 => ...;
          when others => ... ;
       end case;
    end;

arise in practice. I didn't get this done.

====

There is the point mentioned in the !discussion section of this AI:

    3) Do we need to say anything about type invariants? No,
    because if a function has a parameter (or result) of a private type,
    then it's not a static function. But what if it is completed as
    a static expression function after the private type is completed?
    Maybe we need a rule saying that if a type invariant applies to
    a function than the function is not a static expression function
    (like the rule already given for predicates).

I think we do need this rule.

The AI says
  A "static expression function" is defined to be an expression function
     - ...; and
     - ...; and
     - ...; and
     - ...; and
     - ...

I think we need to invent a term for the property implicitly defined in the
section on type invariants
    An invariant is checked upon successful return from any
    call on a subprogram or entry that ...

Something like
     An entry or subprogram is said to be an "invariant
     boundary" entry or subprogram if ...

followed by a use of the new term

     An invariant is check upon successful return from any
     call on an invariant boundary subprogram or entry.

Then we can use the new term to add a new clause to the definition of "static
expression function" along the lines of
    "which is not an invariant boundary subprogram; and"

Other possible names for the new term: "invariant enforcing", "invariant
checking".

====

Opinions?

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  3:16 PM

> It seems clear that compatibility issues are a major concern
> associated with this proposal.

Maybe for some folks.  Expression functions are pretty new!

...
> There is a solution which satisfies both constraints, although I am
> not claiming that it is elegant: we relax the legality rules as per
> Bob's proposal but only in the case of a static expression that
> includes a call to an expression function. Such an expression could
> never currently be static, so this relaxation would not cause us to
> accept something that was previously rejected.

That seems fine to me.

> ...
> I think we need to invent a term for the property implicitly defined
> in the section on type invariants
>   An invariant is checked upon successful return from any
>   call on a subprogram or entry that ...
>
> Something like
>    An entry or subprogram is said to be an "invariant
>    boundary" entry or subprogram if ...

I would somewhat rather associate the notion of boundary with the type being
defined, rather than this one particular aspect that is checked at the
boundary.  Perhaps simply "boundary subprogram for private type T" or
"boundary subprogram for some partial view."  Getting the word invariant there
muddies the waters a bit for me.  The concept of such a boundary exists even
if no invariants have been defined explicitly.

I suppose any term we pick would eventually grow on me... ;-)

...
> Other possible names for the new term: "invariant enforcing",
> "invariant checking".

I find these names even muddier...  I would like to describe the concept,
without talking about what things might happen when crossing that border.
Sort of like calling the border between two countries an "immigration control
line."

> ====
>
> Opinions?

See above.

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

From: Steve Baird
Sent: Thursday, October  5, 2017  3:41 PM

>  I would somewhat rather associate the notion of boundary with the
> type being defined,
I like that idea too.

IIRC, we have wanted a well-defined term for this for other reasons in the
past.

Would precisely defining the boundary for a type also help with the questions
raised in AI12-0210 (Type Invariants and Generics)?

It seems to me that the two issues are related.

Roughly speaking, the idea we are trying to capture here is that a boundary
subprogram for a given private type
    a) can see the implementation of the private type; and
    b) is callable from places that cannot see the implementation
       of the private type; and
    c) has a non-in-mode parameter or a function result of the type.

Right?

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

From: Randy Brukardt
Sent: Thursday, October  5, 2017  3:46 PM

> > It seems clear that compatibility issues are a major concern
> > associated with this proposal.
>
> Maybe for some folks.  Expression functions are pretty new!

Two points on this:

(1) My experience is that once one has expression functions and is used to
the idea, one tends to write everything possible as an expression function.
(This is a problem if you are writing Ada 2005 ACATS tests or for a compiler
that doesn't support them. I've done both. :-)

(2) This compatibility problem exists any time a regular function is changed
into an expression function or vice-versa. It's not just a one time thing.

In particular, I expect Janus/Ada customers to rewrite regular functions into
expression functions in some cases, because Janus/Ada only supports inlining
on expression functions. When that is done, they'd be at risk of running into
these compatibility issues. [Note to any Janus/Ada customers reading this: I'm
speaking in the future tense here. :-)]

...
> > There is a solution which satisfies both constraints, although I am
> > not claiming that it is elegant: we relax the legality rules as per
> > Bob's proposal but only in the case of a static expression that
> > includes a call to an expression function. Such an expression could
> > never currently be static, so this relaxation would not cause us to
> > accept something that was previously rejected.
>
> That seems fine to me.

Cool. I predicted to Steve the opposite. (It is a rather clunky rule, and I
thought you'd object to the "bolted-on" look of it.)

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  6:42 PM

> Roughly speaking, the idea we are trying to capture here is that a
> boundary subprogram for a given private type
>   a) can see the implementation of the private type; and
>   b) is callable from places that cannot see the implementation
>      of the private type; and
>   c) has a non-in-mode parameter or a function result of the type.

I don't understand why you have that last bullet in that form.  Why does the
mode matter?  And are you considering access parameters or access results?
From a SPARK point of view, you will still be presuming the invariant is true
on entry, which you will not be doing for local functions.

> Right?

Modulo my complaint about (c)

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

From: Steve Baird
Sent: Thursday, October  5, 2017  7:08 PM

> I don't understand why you have that last bullet in that form.  Why does the
> mode matter?  And are you considering access parameters or access results?
> From a SPARK point of view, you will still be presuming the invariant is true
> on entry, which you will not be doing for local functions.

Good point about access parameters.

And even for others, I see your point.

There are advantages to ignoring the parameter mode completely (as opposed to
special rules for in-mode non-access parameters) and I don't see any
disadvantages, even if no runtime check is performed in that case.

And of course when I talked about a parameter/result of the private type, I
should have been talking about a parameter/result of a type that has a part
which is of that type.

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  8:05 PM

> Good point about access parameters.
>
> And even for others, I see your point.
>
> There are advantages to ignoring the parameter mode completely (as
> opposed to special rules for in-mode non-access parameters) and I
> don't see any disadvantages, even if no runtime check is performed in
> that case.

Right.  This is another reason I would be reluctant to include the word
"invariant" in the term we end up using.

> And of course when I talked about a parameter/result of the private
> type, I should have been talking about a parameter/result of a type
> that has a part which is of that type.

You could argue that boundary subprograms need not have any parameters or
results of the type.  The key point is that their body has more visibility
on the type than their callers.  They might be passed an access value and
follow it three steps to an object of the private type, and do their thing
there.  SPARK as of today (prior to "safe" pointers) doesn't have this
problem, but presumably in Ada we do have that situation, and SPARK with
safe pointers might have it as well.  So I think the parameter profile might
be irrelevant once you start having pointers.

But now if we bring this back to expression functions -- can they be static
if they have any parameters of an access type?  And I have lost track of what
this whole thing was about -- why are invariant checks a problem?  We don't
want to do them as part of static evaluation?  Why don't we say that a static
expression function must not be the completion of a function declaration.
Hence, if you want a function to be static, give the expression when it is
declared.

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

From: Randy Brukardt
Sent: Thursday, October  5, 2017  8:21 PM

...
> But now if we bring this back to expression functions -- can they be
> static if they have any parameters of an access type?
>  And I have lost track of what this whole thing was about -- why are
> invariant checks a problem?

From memory, we don't want any checks that might fail in a static function
call. We disallow predicates, and Steve decided we needed to do the same
for any invariant checks.

Making the function visible without a completion doesn't completely
eliminate the problem, as an invariant can be visibly defined and so can
an expression function of a private type.

Moreover, I already strongly dislike the fact that the implementation of a
static function has to be exposed. It makes them go contrary to the basic
point of Ada (a strong separation between specification and implementation).
Making that problem worse doesn't improve the AI in my view.

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  9:43 PM

This surprises me.  What is the purpose of a static function if you don't
know it is static and cannot use it as one?  At least with this AI, the only
way you know that an expression function is a static function is by looking
at its defining expression.  I suppose if there were an aspect "Static" or
equivalent, then you could postpone the "body" of the expression function to
the private part.  Am I missing something?

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

From: Randy Brukardt
Sent: Thursday, October  5, 2017  10:01 PM

> This surprises me.  What is the purpose of a static function if you
> don't know it is static and cannot use it as one?

One could argue "approximately the same as any other user-defined static
function", but that's a discussion for a different time.

... > At least with this AI, the only way you know that an expression
> function is a static function is by looking at its defining
> expression.  I suppose if there were an aspect "Static" or equivalent,
> then you could postpone the "body" of the expression function to the
> private part.  Am I missing something?

There surely should be a "Static_Possible" aspect, which among other things
would allow deferring the expression elsewhere (probably not to a body, though,
as the compiler has to be able to see a static expression that it is
evaluating). It certainly would be needed should we ever try to expand static
processing to user-defined static expressions. (Jeff told me privately that
the UK would like to see static expression processing regularized. I think
we've already rejected that idea for this cycle, but I think we need to leave
the possibility open.)

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  10:57 PM

> There surely should be a "Static_Possible" aspect, which among other
> things would allow deferring the expression elsewhere (probably not to
> a body, though, as the compiler has to be able to see a static
> expression that it is evaluating).

I am dubious.  Static expressions can affect legality, so you really have to
know what the function is computing.  There really can't be any "abstraction"
here to speak of.

> It certainly would be needed should we ever try to expand static
> processing to user-defined static expressions. (Jeff told me privately
> that the UK would like to see static expression processing
> regularized. I think we've already rejected that idea for this cycle,
> but I think we need to leave the possibility open.)

I think you are talking about a completely different AI than this one.  Given
the current AI, there seems no particular value to allowing a static
expression function to be a completion.

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

From: Randy Brukardt
Sent: Thursday, October  5, 2017  11:11 PM

...
> I think you are talking about a completely different AI than this one.
> Given the current AI, there seems no particular value to allowing a
> static expression function to be a completion.

Yes, a different (and future) AI. But I don't want this AI to prevent that AI
from being possible.

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

From: Tucker Taft
Sent: Thursday, October  5, 2017  11:04 PM

> Yes, a different (and future) AI. But I don't want this AI to prevent
> that AI from being possible.

Right.  But being *more* restrictive than absolutely necessary is our usual
approach.  By requiring static expression functions to be defined where they
are declared, we are keeping this AI simpler, and allowing ourselves to relax
the restrictions later.

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

From: Steve Baird
Sent: Thursday, October  5, 2017  11:09 PM

>   And I have lost track of what this whole thing was about -- why are
> invariant checks a problem? We don't want to do them as part of static
> evaluation?

Exactly.

>  Why don't we say that a static expression function must not be the
> completion of a function declaration.

Sounds like a nice clean solution; I like it.

It is inconsistent with our treatment of deferred constants (because a use of
a deferred constant can be static if the completion is visible), but that's ok
I suppose.

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

From: Steve Baird
Sent: Friday, October  6, 2017  11:26 AM

> It is inconsistent with our treatment of deferred constants (because a
> use of a deferred constant can be static if the completion is
> visible),

Do we decide whether an expression function is a static expression function
when the function is declared or when it is used?

Consider:

     package Pkg is
        type T is private;
        Dc : constant T;
        function Expr_Func return T is (Dc);
     private
        type T is new Integer;
        Dc : constant T := 0;
        Named_Number : constant := Expr_Func; -- legal?
     end;

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

From: Randy Brukardt
Sent: Monday, October  9, 2017  7:07 PM

>> There surely should be a "Static_Possible" aspect, which among other
>> things would allow deferring the expression elsewhere (probably not
>> to a body, though, as the compiler has to be able to see a static
>> expression that it is evaluating).

>I am dubious.  Static expressions can affect legality, so you really
>have to know what the function is computing.  There really can't be any
>"abstraction" here to speak of.

The only reason to write a static function in the first place is to provide
some "abstraction". Else it is just useless complication for the reader. If
you are right here, then there shouldn't be any static functions to begin
with.

...
> >>> It certainly would be needed should we ever try to expand static
> >>> processing to user-defined static expressions. (Jeff told me
> >>> privately that the UK would like to see static expression
> >>> processing regularized. I think we've already rejected that idea
> >>> for this cycle, but I think we need to leave the possibility
> >>> open.)
> >>
> >> I think you are talking about a completely different AI than this
> >> one.  Given the current AI, there seems no particular value to
> >> allowing a static expression function to be a completion.
> >
> > Yes, a different (and future) AI. But I don't want this AI to
> > prevent that AI from being possible.
>
> Right.  But being *more* restrictive than absolutely necessary is our
> usual approach.  By requiring static expression functions to be
> defined where they are declared, we are keeping this AI simpler, and
> allowing ourselves to relax the restrictions later.

Such a future AI would have to have a way (almost certainly an aspect) to mark
completions that are static functions. (A "generalization" proposal that
doesn't support private types is not really fixing anything, IMHO.) An AI that
has some sort of automatic static functions is going to conflict with that
future AI, as there would be a mismash of automatic and declared static
functions, and probably conflicts in some cases. Automatic static functions
is a dead-end that would pretty much prevent any further changes to static
processing.

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

From: Tucker Taft
Sent: Monday, October  9, 2017  8:45 PM

>> Right.  But being *more* restrictive than absolutely necessary is our
>> usual approach.  By requiring static expression functions to be
>> defined where they are declared, we are keeping this AI simpler, and
>> allowing ourselves to relax the restrictions later.
>
> Such a future AI would have to have a way (almost certainly an aspect)
> to mark completions that are static functions. (A "generalization"
> proposal that doesn't support private types is not really fixing
> anything, IMHO.) An AI that has some sort of automatic static
> functions is going to conflict with that future AI, as there would be
> a mismash of automatic and declared static functions, and probably
> conflicts in some cases. Automatic static functions is a dead-end that
> would pretty much prevent any further changes to static processing.

I could see adding an aspect to claim that something is a static function,
and the compiler would check to be sure the expression then and there.  We
could provide a configuration pragma some day to make it automatic, I suppose.

But I still don't get how you can complete a static function in a private part
or a body, if it is going to be static outside the package as well.  Because
the *values* returned by the function can really matter to the caller, as they
determine legality, and in some weird cases, can even determine the type (e.g.
A'First(N) where "N" is a static expression function).

Are you proposing that inside the package the function can be static, but not
outside?  I suppose I could see some value in that.  I think that is how
deferred constants work.  But I was getting the impression you wanted the
"I_Am_Static" aspect on the visible declaration of the function, but not
provide the body there as well.  That is what I don't understand...

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

From: Randy Brukardt
Sent: Monday, October  9, 2017  9:21 PM

...
> But I still don't get how you can complete a static function in a
> private part or a body, if it is going to be static outside the
> package as well.  Because the *values* returned by the function can
> really matter to the caller, as they determine legality, and in some
> weird cases, can even determine the type (e.g. A'First(N) where "N" is
> a static expression function).

I don't get this obsession with values. The first thing an Ada programmer
learns is to use names rather than literals. And I have to assume the desire
to use expression functions in static expressions is to get more abstraction
into the expression.

Yes, the value can determine legality. But so what? If the function implements
a sensible, well-documented abstraction, it will work fine without worrying
about the exact value returned. If it doesn't, well, we can't legislate
perfection. I doubt very much that you care about the values of expressions in
your program unless the compiler rejects them. That certainly would be the
case here.

> But I was getting the impression you wanted the "I_Am_Static"
> aspect on the visible declaration of the function, but not provide the
> body there as well.  That is what I don't understand...

What about "abstraction" do you not understand?? Why you think these functions
are somehow different than any other function ever written is what I don't
understand. Any function someone writes might return a value other than one
expected. Whether that makes the program illegal or just raises an exception
doesn't change the response to it much. The programmer then has to look at the
function body to see why an incorrect value was returned -- but that's the
only time that one would look at the function body.

If static expression functions aren't going to be used to provide abstraction,
what else could they possibly be good for?? As I previously said, if they
don't provide abstraction, then they aren't providing anything at all, and we
should simply forget this idea.

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

From: Steve Baird
Sent: Wednesday, January  5, 2018  6:43 PM

Another iteration of this AI. [This is version /05 of this AI - ED.]

We address all the compatibility issues by saying that you don't get a static
expression function unless you ask for it by specifying a new aspect (named
Static).

[At some later date, we might consider defining a configuration pragma which
says that the default value of the Static aspect of a potentially static
expression function is True, not False. That's not currently part of this AI.]

We address all the confusion associated with having a function sometimes be a
static function and sometimes not (depending on whether the expression
function completion is visible) by saying that an expression function which is
a completion is never a static function. Thus, all views of a function agree
on this point.

We address the interactions with type invariants by making a textually large
but semantically small change to type invariants (no change to type invariants
except that we get a new term defined to identify a boundary subprogram).

Feedback, as always, is appreciated.

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

From: Jeff Cousins
Sent: Friday, January 12, 2018  7:15 AM

Thanks Steve.

"In 7.3.2, add the following at the end of the Static semantics section.


If one or more invariant expressions apply to a nonabstract type T, then
a subprogram or entry is said to be "type invariant enforcing" for T if
   - it is the Read or Input stream-oriented attribute of the type T; or"

It seems strange to think of an attribute as a subprogram or entry – would
attribute reference be better?

You’ve lost the words added by AI12-0193 (i.e. "In the case of a call to a
protected operation, the check is performed before the end of the protected
action. In the case of a call to a task entry, the check is performed before
the end of the rendezvous."

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

From: Tucker Taft
Sent: Friday, January 12, 2018  11:27 AM

...
> It seems strange to think of an attribute as a subprogram or entry – would
> attribute reference be better?

We use the terminology Steve is using in general.  See the definition of
'Write, for example:

"For every subtype S of a specific type T, the following attributes are defined.
 S'Write
     S'Write denotes a procedure with the following specification: ..."

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

From: Steve Baird
Sent: Friday, January 12, 2018  12:27 PM

> You’ve lost the words added by AI12-0193 (i.e. “In the case of a call
> to a protected operation, the check is performed before the end of the
> protected action. In the case of a call to a task entry, the check is
> performed before the end of the rendezvous.”

Good catch! I agree that we don't want to delete that sentence.
The changes 7.3.2 are intended to introduce the definition of a new term and
otherwise be semantics-preserving.

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

Questions? Ask the ACAA Technical Agent