Version 1.1 of ai05s/ai05-0143-1.txt
!standard 6.01 (18) 09-02-15 AI05-0143-1/01
!standard 6.06 (03)
!standard 9.5.1 (02)
!class Amendment 09-02-15
!status work item 09-02-15
!status received 09-02-15
!subject It's BAAACCKK!!: In Out parameters for functions
Parameters of all modes are allowed in functions.
The restriction on parameter modes for functions is an embarassing wart on
the language. Ada functions can have arbitrary side-effects, but are not
allowed to announce that in their specifications.
When constructing reusable object-oriented abstractions, it is important to
allow future extensions to have the maximum flexibility. This means that
parameters of object-oriented types should generally be declared as in out,
so that future extensions can modify the parameter's contents if necessary.
However, this prevents using functions for most operations. If there is any
conceptual chance of an extension needing to modify its argument, then
a function cannot be used. Even for operations that are conceptually pure,
caching of results may require modification of extensions.
If an unconstrained type (such as String) needs to be returned, there is no
real alternative to using a function.
When this problem occurs, only three solutions are possible:
-- Abandon functions;
-- Use the functions, leaving the onus of solving the problem on
-- Use an access parameter.
For the second solution, the author of an extension would have to allocate (probably
from the heap) a separate, writable object, and include an access to
it in the extension. This means the author now has to handle memory
management (with all of its possibilities for errors, like storage
leaks and double freeing) which they previously did not have to do.
Access parameters are a very flawed solution as well. Access parameters require
altering the calling syntax of calls to the function (to include an approriate
'Access, or to remove a dereference). They also require altering the declaration
of the object to be passed (to include "aliased"). Finally, access parameters
are more expensive at run-time than regular parameter passing, as they are
required to include a run-tine indication of their accessibility level. The
run-time check can even be dangerous, as the check may fail only with
arguments declared in nested scopes, and that may not happen in unit testing.
for all of these reasons, the restriction on parameter modes for functions
has been removed.
The last sentence of 6.1(18) is deleted.
Add "of mode in" to 6.6(3):
The subprogram_specification of a unary or binary operator shall have one or
two parameters of mode in, respectively. A generic function instantiation whose
designator is an operator_symbol is only allowed if the specification of the
generic function has the corresponding number of parameters of mode in and no
Replace 9.5.1(2) by:
Within the body of a protected function (or a function declared immediately
within a protected_body), all of whose parameters have mode in, the current
instance of the enclosing protected unit is defined to be a constant [(that is,
its subcomponents may be read but not updated)]. Within the body of a
protected subprogram other than a function with parameters of mode in (or a
such a subprogram declared immediately within a protected_body), and within
an entry_body, the current instance is defined to be a variable [(updating
The primary technical argument against allowing "in out" and "out" parameters
in function calls is that there is not much visibility of the side-effects,
and thus they make it more likely that order-dependent expressions are created.
However, the existing features of the language (especially the combination
of access parameters and prefix notation) make it possible to write the majority
of examples of incorrect order dependence in Ada as it exists today. Specifically,
access parameters are very similar semantically to "in out" by-reference
parameters, and they are allowed on functions already. They just provide a
less convenient syntax and are less efficient (because of the possibility of
dynamic accessibility checks) than "in out" parameters would be.
As one commenter put described our current situation with incorrect order
dependence, we're already in a deep pit, and if we're not at the bottom
already, we're only a few centimeters above it. Thus, the problem of incorrect
order dependence is one that should be addressed irrespective of "in out"
parameters for functions, and surely should not be used as an excuse to
"throw out the baby with the bathwater". (The problem of incorrect order
dependence is discussed in AI05-0144-1, including plenty of examples.)
Two additional issues are addressed by this change.
Operator symbols are conceptually functions with one or two in parameters.
We do not want infix expressions to have side effects on their arguments.
Thus, we add wording to restrict operator symbols to parameters of mode in.
The unfortunate tying of read-only vs. read-write access to a protected object
to the use of a function or procedure also needs to be changed. We've used the
minimal fix here, which is to say that functions with in out or out parameters
have read-write access to the protected object. A better solution would be
to add a modifier similar to that used for overriding to determine whether a
subprogram has read-only versus read-write access. However, that was rejected
as being too heavy of a solution, particularly as Ada compilers rarely
take advantage of read-only protected object access.
In the Claw Builder, we have a function that can return an
access to the actual Claw object for simulation. This function is usually
used to directly call a dispatching Claw operation:
Claw.Move (Get_Claw_Object (My_Button).all, <new location>);
Because the access returned is never used for more than a single subprogram,
we implemented the function with Unchecked_Access:
function Get_Claw_Object (Window : in Button_Type)
return Claw.Any_Window_Access_Type is
This code is illegal, of course, as Window.My_Button is a constant, and
Any_Window_Access_Type is an access-to-variable. Since Claw.Move takes an
in out parameter, changing Any_Window_Access_Type is out of the question.
Changing this to the "obvious" implementation:
function Get_Claw_Object (Window : access Button_Type)
return Claw.Any_Window_Access_Type is
means that calling objects have to be declared as aliased, and an additional
'Access used. Moreover, there is the run-time overhead of passing an
accessibility level, even though it will never be used in this case.
What we really want, of course, is to write:
function Get_Claw_Object (Window : in out Button_Type)
return Claw.Any_Window_Access_Type is
which we can now do.
Conceptually, of course, the parameter to this function isn't even modified.
We just need to use in out here to prevent someone from passing a constant,
which could cause all manner of trouble.
ACATS tests are needed to test that this is allowed, and that the restrictions
on operator symbols are enforced. Moreover, existing ACATS B-Test tests
prohibiting in out parameters on function needs to be withdrawn.
From: Randy Brukardt, February 15, 2009
Version /01 of this AI is almost identical to the final state of AI95-0323 (when
it was voted no action). The only changes were to incorporate one wording comment
and to add a bit of discussion about the technical issues that were mentioned by
Tucker (see the e-mail toward the end of AI95-0323).
I distinctly remember someone saying "thank goodness that we don't allow "in out"
parameters in functions" during some ARG discussion. I was unable to find that
in the minutes of any ARG meeting or in any AIs. I also spent quite a bit of time
reading old AIs about freezing and incomplete views to see if adding "in out"
parameters would break anything; I was unable to find any rules that would not work
in that context. It's quite possible that the rule under discussion was later
modified eliminating the problem, or perhaps it was never used at all. Or
maybe I just failed to find it.
Questions? Ask the ACAA Technical Agent