# Version 1.15 of ai12s/ai12-0075-1.txt

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

!standard 4.9(21)          18-05-07 AI12-0075-1/11
!standard 6.8(3/4)
!standard 6.8(5/4)
!standard 6.8(6/4)
!standard 7.3.2(8.2/5)
!standard 7.3.2(15/4)
!standard 7.3.2(16/4)
!standard 7.3.2(17/4)
!standard 7.3.2(19/4)
!standard 7.3.2(20/5)
!class Amendment 13-06-09
!status Amendment 1-2012 18-04-06
!status WG9 Approved 16-06-22
!status ARG Approved 10-0-0 18-04-02
!status work item 13-06-09
!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
The aspect Static is introduced. It can only be applied to expression functions and ensures that the expression function can be evaluated statically.
!wording
- a static expression function (see 6.8);
AARM Discussion: The preceding "statically unevaluated" rule allows
X : constant := (if True then 37 else (1 / 0)); -- OK.
but does not allow
function If_Then_Else (Flag : Boolean; X, Y : Integer) return Integer is (if Flag then X else Y) with Static; -- see 6.8 X : constant := If_Then_Else (True, 37, 1 / 0); -- Error.
because evaluation of a function call includes evaluation of all of its actual parameters.
Static Semantics
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.
The following language-defined representation aspect may be specified for an expression function.
Static The type of aspect Static is Boolean. When aspect Static is True for an expression function, the function is a *static expression function*. If directly specified, the aspect_definition shall be a static expression.
The Static value for an inherited function is True if some corresponding primitive function of the parent or progenitor type is a static expression function; otherwise, if not directly specified, the aspect is False.
Redundant[A static expression function is a static function; see 4.9.]
Move 6.8(6/4) before the above test, in order to avoid having two Static Semantics sections in this clause, and to eliminate forward references to the term "expression function".
Add after 6.8(5/4): [In the Legality Rules section].
Aspect Static shall be specified to have the value True only if the associated expression_function_declaration:
- is not a completion; - has an expression that is a potentially static expression; - contains no calls to itself; - each parameter (if any) is of mode IN and is of a
static subtype;
- has a result subtype that is a static subtype; - has no applicable precondition or postcondition expression; and - is not type-invariant preserving for any type (see 7.3.2).
AARM Ramification: Since a string subtype can be static, this allows an expression function of a string type to be static.
If one or more invariant expressions apply to a nonabstract type T, then a subprogram or entry is said to be type-invariant preserving for T if
- 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), or is the Read or Input stream-oriented attribute 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.
- and at least one of the following applies to the callable entity:
* has a result with a part of type T;
* has one or more *out* or *in out* parameters with a part of type T;
* 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.
Each such part of type T is said to be "subject to an invariant check" for T.
Replace 7.3.2(15/4-20/5) with: [as modified by AI12-0193-1]
Upon successful return from a call on any subprogram or entry which is type-invariant preserving for @i<T>, an invariant check is performed on each part of type T which is subject to an invariant check for T. 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.
!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.
This version incorporates feedback from the Vienna and Lexington meetings (#57 & 58) 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.
We use aspect Static to declare static expression functions, as it is unsafe for a function to change from being non-static to static (or the reverse). Such a change can cause code to change results or even be illegal - especially a problem for existing Ada 2012 code where automatically determining staticness can cause compatibility problems.
Specifically:
* whether or not an expression is static potentially changes legality of the expression. There are three known ways for an expression function call to change the legality of an expression depending on whether or not the function is considered static. Explicitly declaring static functions means that the legality of uses far away don't change due to simple maintenance changes, and the legality of existing code doesn't change simply by compiling in Ada 2020 mode rather than Ada 2012 mode.
* the value of a real static expression is likely to be different than the value of the equivalent non-static expression (exact evaluation can give a different answer than runtime evaluation, even after rounding). Changing from one to the other can break careful numerical analysis; doing so implicitly could cause significant problems. Making staticness part of the function declaration avoids this problem.
* if staticness was determined automatically, it could depend on the view of the function as to whether it is known to be static and thus whether the expression it is used in is static. Deferred constants, for instance can be nonstatic in the visible part and static in the private part/body. That would be horribly confusing, thus determining it when the function is declared with aspect Static is preferable.
!example
!corrigendum 4.9(21)
Insert after the paragraph:
• an enumeration literal;
the new paragraph:
• a static expression function (see 6.8);
!corrigendum 6.8(3/4)
Insert after the paragraph:
The expected type for the expression or aggregate of an expression_function_declaration is the result type (see 6.5) of the function.
the new paragraphs:
Static Semantics
An expression_function_declaration declares an expression function. The return expression of an expression function is the expression or aggregate of the expression_function_declaration. A completion is not allowed for an expression_function_declaration; however, an expression_function_declaration can complete a previous declaration.
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".
The following language-defined representation aspect may be specified for an expression function:
Static
The type of aspect Static is Boolean. When aspect Static is True for an expression function, the function is a static expression function. If directly specified, the aspect_definition shall be a static expression.
The Static value for an inherited function is True if some corresponding primitive function of the parent or progenitor type is a static expression function; otherwise, if not directly specified, the aspect is False.
A static expression function is a static function; see 4.9.
!corrigendum 6.8(5/4)
Insert after the paragraph:
If the result subtype has one or more unconstrained access discriminants, the accessibility level of the anonymous access type of each access discriminant, as determined by the expression or aggregate of the expression_function_declaration, shall not be statically deeper than that of the master that elaborated the expression_function_declaration.
the new paragraphs:
Aspect Static shall be specified to have the value True only if the associated expression_function_declaration:
• is not a completion;
• has an expression that is a potentially static expression;
• contains no calls to itself;
• each parameter (if any) is of mode in and is of a static subtype;
• has a result subtype that is a static subtype;
• has no applicable precondition or postcondition expression; and
• is not type-invariant preserving for any type (see 7.3.2).
!corrigendum 6.8(6/4)
Delete the paragraph:
An expression_function_declaration declares an expression function. The return expression of an expression function is the expression or aggregate of the expression_function_declaration. A completion is not allowed for an expression_function_declaration; however, an expression_function_declaration can complete a previous declaration.
!corrigendum 7.3.2(8/3)
Replace the paragraph:
If the Type_Invariant'Class aspect is specified for a tagged type T, then the invariant expression applies to all descendants of T.
by:
If the Type_Invariant'Class aspect is specified for a tagged type T, then a corresponding expression also applies to each nonabstract descendant T1 of T (including T itself if it is nonabstract). The corresponding expression is constructed from the associated expression as follows:
If one or more invariant expressions apply to a nonabstract type T, then a subprogram or entry is said to be type-invariant preserving for T if
• 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), or is the Read or Input stream-oriented attribute 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.
• and at least one of the following applies to the callable entity:
• has a result with a part of type T;
• has one or more out or in out parameters with a part of type T;
• 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.
Each such part of type T is said to be subject to an invariant check for T.
!corrigendum 7.3.2(15/4)
Replace the paragraph:
• After a successful call on the Read or Input stream attribute of the type T, the check is performed on the object initialized by the stream attribute;
by:
• Upon successful return from a call on any subprogram or entry which is type-invariant preserving for T, an invariant check is performed on each part of type T which is subject to an invariant check for T. 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;
!corrigendum 7.3.2(16/4)
Delete the paragraph:
• An invariant is checked upon successful return from a call on any subprogram or entry that:
!corrigendum 7.3.2(17/4)
Delete the paragraph:
• is declared within the immediate scope of type T (or by an instance of a generic unit, and the generic is declared within the immediate scope of type T),
!corrigendum 7.3.2(19/3)
Delete the paragraph:
• has a result with a part of type T, or one or more parameters with a part of type T, or an access to variable parameter whose designated type has a part of type T.
!corrigendum 7.3.2(20/3)
Delete the paragraph:
The check is performed on each such part of type T.
!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

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

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

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.]

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
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?

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

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.

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.

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

From: Randy Brukardt
Sent: Thursday, January 18, 2018  1:03 AM

> > 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.

True, but not critical; your editor is used to merging wording from AIs that
change the same paragraph. There'd only be a problem if the AI specifically
mentioned the old AI (193 in this case) and THEN left out the words.
Otherwise, it's just two insertions into the same paragraph.

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

From: Randy Brukardt
Sent: Thursday, January 18, 2018  1:41 AM

> Another iteration of this AI.

Here are my editorial comments on this AI:

> Add to the definition of static function (i.e. insert as the
> penultimate item of the 4.9 (19-22) list):

We don't describe changes this way; we always use the paragraph number in the
RM. You can put a comment in square brackets after the actual change, thus:

>   - a static expression function (see 6.8)

This needs to end with a semicolon to look like the other bullets in this group.

> Add at the and of the 4.9 "Legality Rules" section:

Same here, this should be:

> Introduce a "Static Semantics" section for 6.8 immediately before the
> "Legality Rules" section, containing:

Yet again. The header "Static Semantics" should just be part of the new
wording. Thus:

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

Broken record time. This should say:

>In the Dynamic Semantics section, replace 7.3.2(15/4-20/5) with:

The first part isn't needed.

I added the two sentences from AI12-0193-1 to this new paragraph (at the end).

In the discussion:
> This version incorporates feedback from the last two meetings so that

No one reading this in the distant future will have any idea of what two
meetings you are talking about. That matters if they want to look up the
associated minutes. It should say something like "Vienna and Lexington meetings"
possibly with the meeting numbers as well (since it appears that there will
be another Lexington meeting).

I've made these changes and posted the result as version /06.

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

From: Randy Brukardt
Sent: Thursday, January 18, 2018  2:37 AM

> Another iteration of this AI.

sent in a previous message).

>
>  Static Semantics

This gives this relatively small subclause two Static Semantics sections.
While that isn't prohibited, we do try to avoid having multiple occurrences of
the same section. Assuming this cannot be after 6.8(6/4), probably it would be
best to move 6.8(6/4) after this wording so that there is one such section.

----

>  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.

"Static subtype" includes "static string subtypes". Are we intending to allow
expression functions to be static for string-valued expressions? We don't allow
that for attributes, so that would seem to be an expansion. (I don't feel
strongly either way, it just seems like something that should be done
consciously, not be accident.)

----

>  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].

The definition of this aspect seems too minimal. There ought to be some
description of what it is for, what the value is if not specified, and usually
some discussion of inheritance. See the wording for No_Return for a model. (I
note that you left out the part about the value of the aspect being required to
be static; I don't think we want to be determining staticness at runtime. :-)

I also think that we have to be careful about defining this (or any other)
aspect too narrowly. As such, I think it would be better to define this for all
expression functions (or maybe even all functions), and then use Legality Rules
to prevent setting it to True anywhere except where it is meaningful. That will
help if we ever want to expand the definition of staticness to include
completions or other kinds of types.

Aside: Should this be possible for a generic function or instance thereof? An
expression function can complete a generic function. Humm, I suppose the "no
completions" takes care of that, too.

Anyway, I suggest something more like:

The following language-defined representation aspect may be specified
for an expression function.

Static   The type of aspect Static is Boolean. When aspect Static is True
for an expression function, the function is a *static expression
function*. If directly specified, the aspect_definition shall be a
static expression.

<Some inheritance rule here>; otherwise, if not directly
specified, the aspect is False.

Redundant[A static expression function is a static function; see 4.9.]

I have <Some inheritance rule here> because the one you have isn't right. It
says:

>  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.

Channeling what you did to me when working on the Nonblocking aspect, what does
this mean if there are multiple corresponding subprograms?? (That is, inherited
from multiple progenitors (or a parent)).

As it stands, no progenitor primitive could be an expression function (there is
a use for that, but we've never wanted do the work), so one solution would be to
talk only about the parent. But if we start allowing completions or expression
functions in progenitors, such a rule would fall over, so assuming that
introduces a (Standard) maintenance hazard.

Maybe it would be better to say "if {some}[the] corresponding primitive
function". In any case, this ought to be reworded in terms of inheritance of the
aspect.

I also wonder if we actually need the term "static expression function".
Can't we just say "an expression function with the Static aspect True" in the
handful of places where we need the term? (That's especially true as
"potentially static expression function" could be confused with "static
expression function".)

Anyway, with the proposed rewording, we need a Legality Rule:

Aspect Static shall only be specified to have the value True if the associated
expression function is a potentially static expression function.

If we reordered this clause as I suggested, that would naturally go after
6.8(5/4).

----

>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.

This isn't semantics preserving for the Read and Input attributes. In the
original text, they are a further level out from the other two bullets, and both
of the other bullets apply to other subprograms, while Read and Input
unconditionally check their result.

The original bullet for Read/Input said:

After a successful call on the Read or Input stream-oriented stream attribute of
the type T, the check is performed on the object initialized by the attribute;

I don't see how you can get that semantics from the above text. (I'm also not
sure what object is getting "initialized" by either of these attributes -- for
Read, an out parameter is being written, and for Input, there is a function
result. Neither of these are formally "initialization". Perhaps you were trying
to make sense of this wording??)

In any case, the original semantics seems to be that an invariant check is
performed the out parameter of Read and the function result of Input, regardless
of where they appear. And there is no rule about "parts" in this case. While
"parts" might be an omission (or not; it's gotten too late to continue to think
same sort of rule applies to initialization by default, after all).

The one good thing about moving this to Static Semantics is that we can justify
the use of static determination of parts much easier when the rule in question
is clearly static.

But I can't tell how you determine what is "subject to an invariant check" for
Read or Input, especially in the case where the default implementation is used
(and thus there is no declaration of a subprogram to fall back on).

----

Gaaa!! It's 2:30 AM!! I need to go home!! Luckily, I'm done reviewing this AI.

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

From: Steve Baird
Sent: Thursday, January 18, 2018  3:37 PM

> Here are my substantive comments for discussion (the editorial
> comments were sent in a previous message).
>
>
>>
>>   Static Semantics
>
> This gives this relatively small subclause two Static Semantics sections.
> While that isn't prohibited, we do try to avoid having multiple
> occurrences of the same section. Assuming this cannot be after
> 6.8(6/4), probably it would be best to move 6.8(6/4) after this
> wording so that there is one such section.
>

Makes sense. I didn't mean to introduce two Static Semantics sections.

> ----
>
>>   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.
>
> "Static subtype" includes "static string subtypes". Are we intending
> to allow expression functions to be static for string-valued
> expressions? We don't allow that for attributes, so that would seem to
> be an expansion. (I don't feel strongly either way, it just seems like
> something that should be done consciously, not be accident.)

Good point. I agree that we could go either way on this question; there are
reasonable arguments on both sides. If we do decide to allow this, then we
should include an AARM note to make things clear.

> ----
>
>>   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].
>
> The definition of this aspect seems too minimal. There ought to be
> some description of what it is for, what the value is if not
> specified, and usually some discussion of inheritance. See the wording
> for No_Return for a model. (I note that you left out the part about
> the value of the aspect being required to be static; I don't think we
> want to be determining staticness at runtime. :-)

I agree that the aspect value needs to be static.

> I also think that we have to be careful about defining this (or any
> other) aspect too narrowly. As such, I think it would be better to
> define this for all expression functions (or maybe even all
> functions), and then use Legality Rules to prevent setting it to True
> anywhere except where it is meaningful. That will help if we ever want
> to expand the definition of staticness to include completions or other kinds
> of types.

This is just a matter of presentation. We could say

The Lumpy aspect may be specified for a slimy galumph.
or
The Lumpy aspect may be specified for a galumph.
Legality Rules
The Lumpy aspect shall not be specified for a non-slimy galumph.

and it has no effect on the language definition. It's just a matter of what is

If we later decide that it makes sense to allow a lumpy-but-not-slimy galumph,
then having to modify the first version doesn't seem very hard. We'd probably
have to add wording in that neighborhood in either case in order to give rules
for the new construct.

I think the presentation I proposed (i.e., defining the term "potentially
static expression function") is the most readable of the alternatives that I
considered, but we can certainly discuss other formulations.

> Anyway, I suggest something more like:

You get kudos in any case just for suggesting a concrete alternative.

>
>     The following language-defined representation aspect may be specified
>     for an expression function.
>
>       Static   The type of aspect Static is Boolean. When aspect Static is
>                True for an expression function, the function is a *static
>                expression function*. If directly specified, the
>                aspect_definition shall be a static expression.
>
>                <Some inheritance rule here>; otherwise, if not directly
>                specified, the aspect is False.
>
>     Redundant[A static expression function is a static function; see 4.9.]
>
> I have <Some inheritance rule here> because the one you have isn't right. It
> says:
>
>>   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.
>
> Channeling what you did to me when working on the Nonblocking aspect,
> what does this mean if there are multiple corresponding subprograms??
> (That is, inherited from multiple progenitors (or a parent)).

It means that when somebody proposes a language change that allows an
expression function as primitive operation of an interface type, then that
person has some work to do in this area. I don't think this is ever going to
happen (see all the grief that came from allowing null procedures as primitives
for interface types and the "one is chosen arbitrarily" rule in 8.3).

> As it stands, no progenitor primitive could be an expression function
> (there is a use for that, but we've never wanted do the work), so one
> solution would be to talk only about the parent.

I believe my proposed wording does this, at least in effect.

> But if we start allowing completions
> or expression functions in progenitors, such a rule would fall over,
> so assuming that introduces a (Standard) maintenance hazard.

I don't give much weight to this because (as noted above) I don't think the
kind of change that would demonstrate this problem is very likely.
On the other hand, for example, I think it would be more likely that someday
we might want to allow a static view of an expression function which is a
completion if the completion is appropriately visible (which would need to be
defined).

> Maybe it would be better to say "if {some}[the] corresponding
> primitive function". In any case, this ought to be reworded in terms
> of inheritance of the aspect.
>
> I also wonder if we actually need the term "static expression function".
> Can't we just say "an expression function with the Static aspect True"
> in the handful of places where we need the term? (That's especially
> true as "potentially static expression function" could be confused
> with "static expression function".)
>
> Anyway, with the proposed rewording, we need a Legality Rule:
>
> Aspect Static shall only be specified to have the value True if the
> associated expression function is a potentially static expression function.

> If we reordered this clause as I suggested, that would naturally go
> after 6.8(5/4).

basis of readability and clarity, as opposed to trying to ease future possible
changes to the language. I'm not against avoiding maintenance hazards in
general (quite the contrary! And I also like apple pie), but in this particular
case ... well, I've stated my opinion above.

> In any case, the original semantics seems to be that an invariant
> check is performed the out parameter of Read and the function result
> of Input, regardless of where they appear. And there is no rule about
> "parts" in this case.

Agreed.

> While "parts" might be an omission (or not; it's gotten too late to
> is certainly intended (the same sort of rule applies to initialization
> by default, after all) >

An object of type T cannot have a subcomponent of type T, so I believe the
change I suggested is semantics-preserving. Can you sketch out a
counterexample?

> The one good thing about moving this to Static Semantics is that we
> can justify the use of static determination of parts much easier when
> the rule in question is clearly static.
>
> But I can't tell how you determine what is "subject to an invariant check"
> for Read or Input, especially in the case where the default
> implementation is used (and thus there is no declaration of a subprogram to
> fall back on).

The profile of Read or Input is well-defined in that case and so the usual
rules are followed. Would an AARM note clarifying this help?

> Gaaa!! It's 2:30 AM!! I need to go home!! Luckily, I'm done reviewing
> this AI.

You really think you are done?

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

From: Randy Brukardt
Sent: Thursday, January 18, 2018  4:20 PM

...
> > I also think that we have to be careful about defining this (or any
> > other) aspect too narrowly. As such, I think it would be better to
> > define this for all expression functions (or maybe even all
> > functions), and then use Legality Rules to prevent setting it to
> > True anywhere except where it is meaningful. That will help if we
> > ever want to expand the definition of staticness to include
> completions or other kinds of types.
> >
>
> This is just a matter of presentation. We could say
>
>     The Lumpy aspect may be specified for a slimy galumph.
> or
>     The Lumpy aspect may be specified for a galumph.
>    Legality Rules
>     The Lumpy aspect shall not be specified for a non-slimy galumph.
>
> and it has no effect on the language definition. It's just a matter of
> what is clearer for human readers.

True, but your presentation requires the introduction of more terms
(specifically, "static expression function"). If the aspect is defined for
all expression functions, then one simply can talk about the value of the
aspect and avoid defining terms. (Probably one could get rid of "potentially
static expression function" as well, as that is only used in the Legality
Rule; one could simply put all of the conditions into the Legality Rule and
forget the term).

All things being equal, we usually prefer the introduction of fewer terms,
because it decreases the cognitive load on readers. I realize that things
aren't always equal.

My suggestion to eliminate the term "potentially static expression function"

Aspect Static shall only be specified to have the value True if the
associated 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.

I don't think the term is used anywhere else, and it puts the entire Legality
Rule in one place.

> If we later decide that it makes sense to allow a lumpy-but-not-slimy
> galumph, then having to modify the first version doesn't seem very
> hard. We'd probably have to add wording in that neighborhood in either
> case in order to give rules for the new construct.

I suppose, but some of these rules are really obscure (especially if the use
of expression functions is expanded -- will someone remember to update these
rules??).

> I think the presentation I proposed (i.e., defining the term
> "potentially static expression function") is the most readable of the
> alternatives that I considered, but we can certainly discuss other
> formulations.

I think it defines a whole bunch of similar terms which are only used once (and
not even recursively). I'd like to reduce the number of such terms.

...
> > I have <Some inheritance rule here> because the one you have isn't
> > right. It says:
> >
> >>   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.
> >
> > Channeling what you did to me when working on the Nonblocking
> > aspect, what does this mean if there are multiple corresponding subprograms??
> > (That is, inherited from multiple progenitors (or a parent)).
>
> It means that when somebody proposes a language change that allows an
> expression function as primitive operation of an interface type, then
> that person has some work to do in this area. I don't think this is
> ever going to happen (see all the grief that came from allowing null
> procedures as primitives for interface types and the "one is chosen
> arbitrarily" rule in 8.3).

You seem to have missed my point. If there is inheritance, there could be
multiple "corresponding primitive functions". For instance, there could be one
corresponding primitive function that is not an expression function and one
that is an expression function (for the sake of discussion, assume that this
one could have the aspect, so we don't get bogged down about the exact rules
for the aspect). The wording doesn't say at all which one is being talked
about; both of them are "corresponding primitive functions". But one has the
aspect (and can inherit it) and the other does not. What happens in this case
(especially if the one with the aspect has the value True)?

There is no "THE corresponding primitive function" in that case. I suggested at
least saying "some corresponding primitive function" if you want to ignore all
of them but the (single) expression function. I could live with that (not
thrilled as noted elsewhere), but what you have does NOT work if there are
multiple inherited functions. However, a rule like that would mean that
staticness would again be view-specific (coming through the interface would
not be static, while coming through the concrete parent would be).
Maybe it doesn't matter -- do you have a rule disallowing a dispatching call
from being static?

...
> > If we reordered this clause as I suggested, that would naturally go
> > after 6.8(5/4).
>
> the basis of readability and clarity, as opposed to trying to ease
> future possible changes to the language. I'm not against avoiding
> maintenance hazards in general (quite the contrary! And I also like
> apple pie), but in this particular case ... well, I've stated my
> opinion above.

Fair enough. Maintenance was the main reason that came to mind at 2 am, but
having slept on it, I think reducing the number of terms needed is a more
important benefit. Also, writing this aspect more like other similar aspects
(No_Return, Nonblocking at least) is better for consistency of the Standard.

...
> > But I can't tell how you determine what is "subject to an invariant
check"
> > for Read or Input, especially in the case where the default
> > implementation is used (and thus there is no declaration of
> a subprogram to fall back on).
> >
>
> The profile of Read or Input is well-defined in that case and so the
> usual rules are followed. Would an AARM note clarifying this help?

No. The real problem is the structure of the bullets. You have three top-level
bullets, but they are combined as follows:

Bullet1 or (Bullet2 and Bullet3)

[At least, that is how they are combined in the original text.]

And that doesn't work, because you can't have different conjunctions between
bullets of the same level.

Moreover, organized as I have them above, there is nothing that says for
bullet1 what parts of the operation are checked (that's only mentioned in
bullet2, and that is "or"ed with bullet1).

In the original wording, bullet1 is out a level from bullets 2 and 3. I
understand why you want to avoid that, but the way you have the wording doesn't
work.

> > Gaaa!! It's 2:30 AM!! I need to go home!! Luckily, I'm done
> > reviewing this AI.
>
> You really think you are done?

Just for last night. I didn't think it would take a whole hour to write up what
I thought was a short message (until I stumbled onto the progenitor inheritance
and bullet ordering issues). By the time I got done, I was too asleep to care
much more. I figured I'd have to convince you/the group of some of the changes
going forward, but sleep came first.

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

From: Steve Baird
Sent: Friday, January 19, 2018  12:06 PM

> My suggestion to eliminate the term "potentially static expression function"
>
>    Aspect Static shall only be specified to have the value True if the
>    associated 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.
>
>
...
>
> I think it defines a whole bunch of similar terms which are only used
> once (and not even recursively). I'd like to reduce the number of such terms.
>

That's a more convincing argument (IMO). I like your version.

> ...

> You seem to have missed my point. If there is inheritance, there could
> be multiple "corresponding primitive functions". For instance, there
> could be one corresponding primitive function that is not an
> expression function and one that is an expression function (for the
> sake of discussion, assume that this one could have the aspect, so we
> don't get bogged down about the exact rules for the aspect). The
> wording doesn't say at all which one is being talked about; both of
> them are "corresponding primitive functions". But one has the aspect
> (and can inherit it) and the other does not. What happens in this case
> (especially if the one with the aspect has the value True)?

Could you provide an example? A given inherited function comes from exactly
one primitive function of a parent/progenitor type (e.g., that's how formal
parameter names are determined for named-notation calls to the inherited
subprogram), so I don't see the issue.

> There is no "THE corresponding primitive function" in that case.

> I suggested
> at least saying "some corresponding primitive function" if you want to
> ignore all of them but the (single) expression function. I could live
> with that (not thrilled as noted elsewhere), but what you have does
> NOT work if there are multiple inherited functions. However, a rule
> like that would mean that staticness would again be view-specific
> (coming through the interface would not be static, while coming through the
> concrete parent would be). Maybe it doesn't matter -- do you have a rule
> disallowing a dispatching call from being static?

Yes, that is a consequence of the current rules (a tagged formal parameter
would not have a static subtype and you can't have a dispatching call without
a tagged formal parameter).

> ...
>>> If we reordered this clause as I suggested, that would naturally go
>>> after 6.8(5/4).
>>
>> on the basis of readability and clarity, as opposed to trying to ease
>> future possible changes to the language. I'm not against avoiding
>> maintenance hazards in general (quite the contrary! And I also like
>> apple pie), but in this particular case ... well, I've stated my
>> opinion above.
>
> Far enough. Maintenance was the main reason that came to mind at 2 am,
> but having slept on it, I think reducing the number of terms needed is
> a more important benefit. Also, writing this aspect more like other
> similar aspects (No_Return, Nonblocking at least) is better for consistency
> of the Standard.

Agreed.

> ...
>>> But I can't tell how you determine what is "subject to an invariant check"
>>> for Read or Input, especially in the case where the default
>>> implementation is used (and thus there is no declaration of
>> a subprogram to fall back on).
>>>
>>
>> The profile of Read or Input is well-defined in that case and so the
>> usual rules are followed. Would an AARM note clarifying this help?
>
> No. The real problem is the structure of the bullets. You have three
> top-level bullets, but they are combined as follows:
>
>     Bullet1 or (Bullet2 and Bullet3)
>
> [At least, that is how they are combined in the original text.]
>
> And that doesn't work, because you can't have different conjunctions
> between bullets of the same level.
>
> Moreover, organized as I have them above, there is nothing that says for
> bullet1 what parts of the operation are checked (that's only mentioned
> in bullet2, and that is "or"ed with bullet1).
>
> In the original wording, bullet1 is out a level from bullets 2 and 3.
> I understand why you want to avoid that, but the way you have the
> wording doesn't work.

I think I finally understand the issue and I agree with you that there is a
problem. Sometimes it takes me a while.

Would it work to replace

- 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:

with

- 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), or is the Read or Input stream-oriented attribute
of type T, and either:

?

The "and either" part will always be True in the case of T's Read/Input attrs,
but the difference is that the later reference to "Each such part of type T"
would then be well-defined in the Input/Read case.

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

From: Randy Brukardt
Sent: Monday, January 22, 2018  10:49 PM

> > My suggestion to eliminate the term "potentially static expression function"
> > would lead to a Legality Rule that reads something like:
> >
> >    Aspect Static shall only be specified to have the value True if the
> >    associated 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.
> >
> >
> ...
> >
> > I think it defines a whole bunch of similar terms which are only
> > used once (and not even recursively). I'd like to reduce the number of such
> > terms.
>
> That's a more convincing argument (IMO). I like your version.

I don't like it much, I just like it better than yours :-). It needs some
wordsmithing, but that can be done later.

> > ...
>
> > You seem to have missed my point. If there is inheritance, there
> > could be multiple "corresponding primitive functions". For instance,
> > there could be one corresponding primitive function that is not an
> > expression function and one that is an expression function (for the
> > sake of discussion, assume that this one could have the aspect, so
> > we don't get bogged down about the exact rules for the aspect). The
> > wording doesn't say at all which one is being talked about; both of
> > them are "corresponding primitive functions". But one has the aspect
> > (and can inherit it) and the other does not. What happens in this
> > case (especially if the one with the aspect has the value True)?
>
> Could you provide an example? A given inherited function comes from
> exactly one primitive function of a parent/progenitor type (e.g.,
> that's how formal parameter names are determined for named-notation
> calls to the inherited subprogram), so I don't see the issue.

Humm. You are clearly thinking of the rules 8.3(12-12.3). But those rules
don't change the inherited subprograms (they're ALL inherited), those just
change the ones that are *visible*. There's nothing in your wording or in
8.3(12-12.3) that would prevent one from considering them as "corresponding
primitive functions". Just because something is hidden doesn't mean that it
oesn't exist! (I see that one of the AARM notes even mentions that these
hidden items still can be inherited by future derivations.)

[Aside to our newish observers: Yes, this does seem like "angels on a pinhead",
but most of our discussions are more interesting than this. And Steve usually
is the one who comes up with these sorts of subtle distinctions, so I'm happy

> > There is no "THE corresponding primitive function" in that case.

Yes, I certainly agree with this. ;-)

This rule is talking about inheritance from declared functions, and not
talking about visibility at all. 8.3(12-12.3) therefore is irrelevant. QED.

> > I suggested
> > at least saying "some corresponding primitive function" if you want
> > to ignore all of them but the (single) expression function. I could
> > live with that (not thrilled as noted elsewhere), but what you have
> > does NOT work if there are multiple inherited functions.

Note that this entire discussion boils down to changing a single "the" to
"some". Hard to believe you're objecting to that...

...
> > However, a rule
> > like that would mean that staticness would again be view-specific
> > (coming through the interface would not be static, while coming
> > through the concrete parent would be).
> > Maybe it doesn't matter -- do you have a rule disallowing a
> > dispatching call from being static?
>
> Yes, that is a consequence of the current rules (a tagged formal
> parameter would not have a static subtype and you can't have a
> dispatching call without a tagged formal parameter).

I think I realized this when I reread it after sending. This would only become
an issue if we extended staticness to private types and selected record types.
(And we're probably not doing that, even though it would make a lot of sense
for types like Address and Complex.)

...
> No. The real problem is the structure of the bullets. You have three
> > top-level bullets, but they are combined as follows:
> >
> >     Bullet1 or (Bullet2 and Bullet3)
> >
> > [At least, that is how they are combined in the original text.]
> >
> > And that doesn't work, because you can't have different conjunctions
> > between bullets of the same level.
> >
> > Moreover, organized as I have them above, there is nothing that says
> > for bullet1 what parts of the operation are checked (that's only
> > mentioned in bullet2, and that is "or"ed with bullet1).
> >
> > In the original wording, bullet1 is out a level from bullets 2 and 3.
> > I understand why you want to avoid that, but the way you have the
> > wording doesn't work.
>
> I think I finally understand the issue and I agree with you that there
> is a problem. Sometimes it takes me a while.

Not surprising when I was half asleep when I wrote up the original problem.

> Would it work to replace
>
>     - 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:
>
> with
>
>     - 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), or is the Read or Input stream-oriented attribute
>       of type T, and either:
>
> ?
>
> The "and either" part will always be True in the case of T's
> Read/Input attrs, but the difference is that the later reference to
> "Each such part of type T" would then be well-defined in the

I think so, as it gets rid of the mixed and/or. I showed the bullets with
parens, but of course there are no parens between bullets at the same level,
and "A or B and C" is not understandable.

I'll have to look at the entire block to be certain that it works.

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

From: Steve Baird
Sent: Tuesday, January 23, 2018  12:53 PM

>>> I suggested
>>> at least saying "some corresponding primitive function" if you want
>>> to ignore all of them but the (single) expression function. I could
>>> live with that (not thrilled as noted elsewhere), but what you have
>>> does NOT work if there are multiple inherited functions.
> Note that this entire discussion boils down to changing a single "the"
> to "some". Hard to believe you're objecting to that...

No objection now that I understand it.

***************************************************************
```

Questions? Ask the ACAA Technical Agent