Version 1.3 of ai05s/ai05-0143-1.txt

Unformatted version of ai05s/ai05-0143-1.txt version 1.3
Other versions for file ai05s/ai05-0143-1.txt

!standard 6.01 (18)          09-06-27 AI05-0143-1/03
!standard 6.06 (03)
!class Amendment 09-02-15
!status Amendment 201Z 09-06-27
!status ARG Approved 6-0-1 09-06-13
!status work item 09-02-15
!status received 09-02-15
!priority High
!difficulty Medium
!subject In Out parameters for functions
!summary
Parameters of all modes are allowed in functions.
!problem
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
extensions.
-- 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.
!proposal
(See summary.)
!wording
The last sentence of 6.1(18) is deleted.
Revise 6.6(3): The subprogram_specification of a unary or binary operator shall have one or two parameters, respectively. {The parameters shall be of mode in. }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 other parameters}.
!discussion
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.)
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.
We considered using the presence of "in out" parameters on a function to signal that the function needs read-write access to the protected object. This is a capability that is sorely missing from Ada, as the current rules force programmers to use procedures when they really want functions. As noted in the description of the initial problem, it is not always possible to convert a function into a similar procedure call, and even when it is possible, the result is harder to use than necessary.
However, the presense of "in out" parameters doesn't really tell us whether or not we need write access to the protected object; it is perfectly reasonable to modify a parameter but not the protected object. This imperfect description is no better than the current situation in the eyes of some reviewers (an opinion not shared by the author).
In addition, adding read-write function access to protected objects could have a significant impact on implementations. The problem is not judged important enough (and the solution not good enough) in order to incur this impact.
!example
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 begin return Window.My_Button'Unchecked_Access; end Get_Claw_Object;
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 begin return Window.My_Button'Unchecked_Access; end Get_Claw_Object;
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 begin return Window.My_Button'Unchecked_Access; end Get_Claw_Object;
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.
!corrigendum 6.1(18)
Replace the paragraph:
The parameter mode of a formal parameter conveys the direction of information transfer with the actual parameter: in, in out, or out. Mode in is the default, and is the mode of a parameter defined by an access_definition. The formal parameters of a function, if any, shall have the mode in.
by:
The parameter mode of a formal parameter conveys the direction of information transfer with the actual parameter: in, in out, or out. Mode in is the default, and is the mode of a parameter defined by an access_definition.
!corrigendum 6.6(3)
Replace the paragraph:
The subprogram_specification of a unary or binary operator shall have one or two parameters, 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.
by:
The subprogram_specification of a unary or binary operator shall have one or two parameters, respectively. The parameters shall be of mode in. 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 other parameters.
!ACATS test
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 functions need to be withdrawn.
!appendix

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.

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

From: Randy Brukardt, April 30, 2009

The accessibility subcommittee discussed this AI during its conference call today,
and it decided not to make the protected function change. The AI (now version /02)
was thus rewritten to remove this change and discuss the reasons why.

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

Questions? Ask the ACAA Technical Agent