Version 1.5 of ais/ai-00290.txt

Unformatted version of ais/ai-00290.txt version 1.5
Other versions for file ais/ai-00290.txt

!standard 10.2.1 (00)          02-03-14 AI95-00290/00
!class amendment 02-03-13
!status received 02-03-13
!priority Medium
!difficulty Medium
!subject Declaring functions Pure
!summary
!problem
!proposal
!wording
!discussion
!example
!ACATS test
!appendix

From: Tucker Taft
Sent: Tuesday, March 12, 2002  4:47 PM

Thanks, Robert.  I hereby nominate this as the basis for an Amendment AI.
-Tuck

> As Tuck requested:
>
> @item pragma Pure_Function
> @noindent
> Syntax:
>
> @smallexample
> pragma Pure_Function ([Entity =>] function_LOCAL_NAME);
> @end smallexample
>
> This pragma appears in the same declarative part as a function
> declaration (or a set of function declarations if more than one
> overloaded declaration exists, in which case the pragma applies
> to all entities).  If specifies that the function @code{Entity} is
> to be considered pure for the purposes of code generation.  This means
> that the compiler can assume that there are no side effects, and
> in particular that two calls with identical arguments produce the
> same result.  It also means that the function can be used in an
> address clause.
>
> Note that, quite deliberately, there are no static checks to try
> to ensure that this promise is met, so @code{Pure_Function} can be used
> with functions that are conceptually pure, even if they do modify
> global variables.  For example, a square root function that is
> instrumented to count the number of times it is called is still
> conceptually pure, and can still be optimized, even though it
> modifies a global variable (the count).  Memo functions are another
> example (where a table of previous calls is kept and consulted to
> avoid re-computation).
>
> @findex Pure
> Note: Most functions in a @code{Pure} package are automatically pure, and
> there is no need to use pragma @code{Pure_Function} for such functions.  An
> exception is any function that has at least one formal of type
> @code{System.Address} or a type derived from it.  Such functions are not
> considered pure by default, since the compiler assumes that the
> @code{Address} parameter may be functioning as a pointer and that the
> referenced data may change even if the address value does not.  The use
> of pragma @code{Pure_Function} for such a function will override this default
> assumption, and cause the compiler to treat such a function as pure.
>
> Note: If pragma @code{Pure_Function} is applied to a renamed function, it
> applies to the underlying renamed function.  This can be used to
> disambiguate cases of overloading where some but not all functions
> in a set of overloaded functions are to be designated as pure.

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

From: Tucker Taft
Sent: Friday, March 15, 2002  4:23 PM

Robert Dewar wrote:
>
> As Tuck requested:
>
> @item pragma Pure_Function
> @noindent
> Syntax:
>
> @smallexample
> pragma Pure_Function ([Entity =>] function_LOCAL_NAME);
> @end smallexample
>
> This pragma appears in the same declarative part as a function
> declaration (or a set of function declarations if more than one
> overloaded declaration exists, in which case the pragma applies
> to all entities).  If specifies that the function @code{Entity} is
> to be considered pure for the purposes of code generation.  This means
> that the compiler can assume that there are no side effects, and
> in particular that two calls with identical arguments produce the
> same result.  It also means that the function can be used in an
> address clause.

For the RM description, I might recommend a different approach.  Probably start
with the existing rule in 10.2.1(18), where it allows the
compiler to omit a call if the results are not needed, and to reuse
the results of a prior call if the parameters are the "same."
But it would also be useful to go further, and say that the compiler
may reuse the results of a prior call even if some of the parameters
might have changed, so long as the only way they could have changed
is by side-effects of calls on intervening pure subprograms.
This means that the compiler doesn't have to look inside
pure subprograms to see what they might have changed, for the purposes
of eliminating calls on other pure subprograms.

An important feature of the current 10.2.1(18) wording, in my view,
is that it doesn't allow the compiler to "assume" anything which might
turn out to be false, and thereby lead to erroneousness.  It simply
allows the compiler to omit certain calls, and reuse earlier results.
For example, it can't call the same pure function twice, and omit a check
on the second call just because the result of the first call passed
the check.  It has to reuse the result of the first call (which it
checked directly) if it wants to omit the check that might normally
be associated with the second call.

> ...

> @findex Pure
> Note: Most functions in a @code{Pure} package are automatically pure, and
> there is no need to use pragma @code{Pure_Function} for such functions.  An
> exception is any function that has at least one formal of type
> @code{System.Address} or a type derived from it.  Such functions are not
> considered pure by default, since the compiler assumes that the
> @code{Address} parameter may be functioning as a pointer and that the
> referenced data may change even if the address value does not.  The use
> of pragma @code{Pure_Function} for such a function will override this default
> assumption, and cause the compiler to treat such a function as pure.

This discussion seems to be inappropriate for the normative semantics
of the potential amendment.  It might be appropriate to implementation
advice, or perhaps simply to a particular implementation's documentation.

I would hope that every function in a declared Pure package is at
least "officially" Pure, independent of whether it has an Address parameter.
GNAT might choose to not take advantage of the permissions given by
10.2.1(18) in cases where there is an Address parameter, but clearly
some compilers may already be eliminating calls on Pure functions
with Address parameters, and it seems inappropriate to change that
now.

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

From: Robert Dewar
Sent: Friday, March 15, 2002  5:15 PM

Just to be clear, I am offering the current documentation of the pragma
in the GNAT documentation, but certainly not suggesting that this is the
right language for an RM description.

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

From: Tucker Taft
Sent: Tuesday, November 19, 2002  7:50 PM

> Note also that we have in GNAT pragma Pure_Function, so we can get the
> advantages of making functions pure without the burden of making the
> whole package Pure.

And there is an "amendment AI" to add the Pure_Function
pragma to the "standard" set of pragmas, as
it seems useful and of low implementation
burden.

The "defining" semantics for a pure function
is that if you give it the "same" parameters,
you get back the same result.  This is patently
false for a random number generator, so it makes
no sense to make "random" itself pure.

As Robert points out, it is useful to declare
that a function has the "pure" property, even
though it might be implemented in terms of "impure"
units.  That would be the point of the Pure_Function
pragma.

Note that the Pure_Function pragma will not enforce
any restrictions.  It simply informs the reader and
the compiler that it may omit subsequent calls on
the function if the inputs are the same, and simply
reuse the original result.  Note that there is no
guarantee that if you *had* called the function, it would
return the same value.  That would be a bug if it
didn't, presumably, but not erroneous.

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

From: Tucker Taft
Sent: Tuesday, November 19, 2002  7:55 PM

As mentioned in the earlier response, the important
thing to remember is that the compiler may omit
calls on pure functions under certain circumstances,
and reuse the prior returned value.  It is normally a bug
to write a pure function that doesn't return the
same value given the same inputs, but not erroneous.

Another purpose of "Pure" is to support preelaboration.
A final purpose is to allow packages to be
freely replicated in a distributed application without
affecting the semantics.

In retrospect, it was probably a mistake to try to
make the single concept of "Purity" serve all three
roles.  They sometimes conflict with one another.

The Pure_Function pragma is a way to loosen the connection a
bit between these three roles.

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

From: Jean-Pierre Rosen
Sent: Wednesday, November 20, 2002  10:46 AM

Bounded_Error presumably ?

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

From: Robert Dewar
Sent: Wednesday, November 20, 2002  2:38 PM

> As mentioned in the earlier response, the important
> thing to remember is that the compiler may omit
> calls on pure functions under certain circumstances,
> and reuse the prior returned value.  It is normally a bug
> to write a pure function that doesn't return the
> same value given the same inputs, but not erroneous.

It often makes perfectly good sense to return values that are different
from a technical point of view, but the same from a conceptual point of
view. A good example is when an access value is returned, and of course
different pointers might be returned but the conceptual value (the value
pointed to) is always the same. Simple minded string concatenation for
example is in this category if you are dealing with say unbounded strings.

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

From: Tucker Taft
Sent: Tuesday, November 19, 2002  5:51 PM

No, it is not even a bounded error.  The
compiler is not allowed to complain if
it returns a different value.  See
Robert's example of why it might return
a different value, even though it is
"conceptually" pure.

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

!topic implications of pragma pure for Ada.Assertions.Assert
!reference RM95-10.2.1(18)
!from Dan Eilers 03-10-16
!keywords pragma pure assert

The proposed assertions package in AI95-00286 uses pragma pure
(apparently so that procedure Ada.Assertions.Assert can be called
from pure packages).

But this seems to imply an unintended implementation permission to omit
all calls on this procedure, per RM 10.2.1(18), since Assert has only IN
parameters.  I am assuming that an exception being raised is considered
a "side effect" rather than a "result" of the subprogram, although the
RM doesn't seem to explicit say that.

Perhaps there needs to be a mechanism to indicate that a subprogram might
raise an exception, and calls should therefore not be omitted, unless
perhaps they are successive calls with identical parameters.

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

From: Tucker Taft
Sent: Thursday, October 16, 2003  3:00 PM

Good point.  I would instead suggest that we change the wording
of 10.2.1(18) to only apply to functions and to procedures with
OUT parameters.  The permission would not apply to calls on pure
procedures with only IN parameters.

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

From: Robert A. Duff
Sent: Thursday, October 16, 2003  3:04 PM

> But this seems to imply an unintended implementation permission to omit
> all calls on this procedure, per RM 10.2.1(18), since Assert has only IN
> parameters.  I am assuming that an exception being raised is considered
> a "side effect" rather than a "result" of the subprogram, although the
> RM doesn't seem to explicit say that.

Good point.  I've never been very comfortable with the wording of this
paragraph, by the way.

> Perhaps there needs to be a mechanism to indicate that a subprogram might
> raise an exception, and calls should therefore not be omitted, unless
> perhaps they are successive calls with identical parameters.

But surely a user-defined subp call cannot be silently omitted,
just because it is known to raise an exception!?  The AARM annotation
talks about machine-code insertions and the like -- not well-defined
standard stuff like exceptions.

And I think the same about Assert -- if there aren't any pragmas or
command-line switches turning it off, it ought to raise an exception
when violated, just like array-index-out-of-bounds raises C_E.

Or was this intended to be like 11.6?.  I hope not...

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


Questions? Ask the ACAA Technical Agent