!standard 6.01 (18) 10-06-02 AI05-0143-1/04 !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 for 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-time 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 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 presence 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, ); 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) @drepl The @i of a formal parameter conveys the direction of information transfer with the actual parameter: @b, @b, or @b. Mode @b is the default, and is the mode of a parameter defined by an @fa. The formal parameters of a function, if any, shall have the mode @b. @dby The @i of a formal parameter conveys the direction of information transfer with the actual parameter: @b, @b, or @b. Mode @b is the default, and is the mode of a parameter defined by an @fa. !corrigendum 6.6(3) @drepl The @fa of a unary or binary operator shall have one or two parameters, respectively. A generic function instantiation whose @fa is an @fa is only allowed if the specification of the generic function has the corresponding number of parameters. @dby The @fa of a unary or binary operator shall have one or two parameters, respectively. The parameters shall be of mode @b. A generic function instantiation whose @fa is an @fa is only allowed if the specification of the generic function has the corresponding number of parameters of mode @b 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. ****************************************************************