LSN017.AccOOP2 ------------------------ !topic LSN on Access Types and OOP; dispatching; by-ref param passing; etc. !reference MS-3.3.2(5);3.1 !reference MS-3.10(4);3.1 !from Tucker Taft 91-10-29 !updated Tucker Taft 91-12-10 (see end of LSN) !discussion Access types are important for OOP, because it is common to build up heterogeneous linked data structures. Using Ada 9X terminology, the designated type for such access types will generally be T'CLASS, allowing them to designate objects of any type in the class rooted at T. Ada has named access types distinct from the designated type. Operations on an access type are not inherited for a type derived from the designated type. The Ada 9X OOP approach uses the primitive operators of a tagged type T as the "dispatching" operations for T'CLASS. If most manipulations are of objects of some access-to-T'CLASS, then it will be necessary to always explicitly code ".all" when passing them to a dispatching operation. However, there are some situations where it is important to be able to reconstruct the original access value inside the dispatching subprogram, particularly if the dispatching operation is designed to insert the object into a linked data structure. Our current proposal solves this problem by allowing the "aliased" modifier to apply to formal parameters. However, this introduces some additional complexity, while still requiring the use of ".all" at the call site. Here are some of the problems with aliased formal parameters: 1) Although they "look" almost like normal parameters, they require special conformance and scope checks at the call-site, as well as requiring pass-by-reference. Because of this, it will be necessary to include the "modifier" in the definition of "mode conformance" for subprograms to avoid generic contract model violations (currently missing from MS-6.3.1(4);3.1). 2) An explicit ".all" is required at the call-site. 3) The term "aliased" sounds somewhat unpleasant, even though nothing untoward is being done. 4) A 'ACCESS is required to reconstruct the original pointer. We have in the past suggested various other solutions for this problem of dispatching on access types (in particular see an LSN produced by David Rosenfeld from March 5, 1991): a) An implicit T'ACCESS type b) An "access" parameter mode c) A general "adjunct" type concept Given DR comments on the "aliased" formal parameter approach, and the above problems (1)-(4), we are now inspired to reevaluate these and other proposals. The concept of T'ACCESS seems attractive at first, but it has various problems: a1) Dispatching doesn't work right if the parameter is mode OUT, IN OUT, or a function result. a2) The actual parameter will typically be access-to-T1'CLASS, and the type wanted internally will similarly want to be access-to-T2'CLASS (for some T1,T2 appropriately related to T), meaning that T'ACCESS doesn't match correctly on either side. a3) Implicitly declared types have been seen to introduce several problems, because of implicitly declared operations being ambiguous, etc. a4) Dispatching requires dereferencing an access value, yet it would be strange to require all parameters of type T'ACCESS be non-null. The general adjunct type concept is quite complex, and ends up reproducing most of the complexity of generics in a parallel set of capabilities. This leaves the "access" parameter mode (plus possibly other proposals which require a more radical shift in the Ada type model or the proposed OOP approach). The remainder of this LSN will attempt to develop the "access" parameter mode proposal in some depth, and investigate its ramifications. ACCESS PARAMETER MODE Let us define a fourth parameter mode: "access" in conjunction with "in," "in out," and "out." For a formal of "access T" the actual parameter may be either a value of type access-to-T, access-to-T'CLASS, or an aliased object of type T (or T'CLASS). A parameter of mode access is passed by "general access," which means that it corresponds to the representation that is produced by "'ACCESS." The general access value will not be null. CONSTRAINT_ERROR is raised at the call-site if the actual operand is a null access value. "By-access" parameter passing is semantically very similar (identical?) to "by-reference" parameter passing, but is non-optional for mode "access." Within a subprogram with a formal "X: access T" X is considered to be an aliased variable of type T. It may therefore be passed to other subprograms with parameter mode "access" as well as to other operations with in, in-out, or out parameter modes. The attribute 'ACCESS may be applied to X to produce an access value when necessary. The type of X'ACCESS is determined from context. If we look back at the problems associated with aliased formals, we see that this access parameter mode solves (1)-(3). In particular, the parameter mode "access" solves (1) because it is clearly a different mode, so it is not surprising that it has distinct rules and affects subprogram mode conformance. Mode "access" solves (2) because an explicit ".all" is not required. Mode "access" solves (3) because we avoid using "aliased," allowing this modifier to be used only for supporting pointers to stack/statically-allocated objects. "Aliased" is not needed for "normal" programming styles where allocators are acceptable. OTHER RAMIFICATIONS If we do adopt a parameter mode "access," then it is important to examine ramifications elsewhere in the language. A) Functions One immediate question is whether mode "access" should be allowed in functions. As it is essentially semantic sugar for passing an access value, which is already legal in a function, supporting mode "access" should not require any changes in the code generator. This is in contrast to general "in out" parameters for functions, which would require a code generator to support "copy back" after a function call (for elementary types, slices of packed arrays, etc.), and could be a significant change to some compilers which have a tree-oriented intermediate language. It seems reasonable to allow "access T" in a function, since otherwise there is an asymmetry between procedures and functions, where procedures can dispatch on access values, whereas functions cannot. B) Non-null access parameters An additional ramification is that "access T" provides a way of "pushing" the non-null access check to the caller, without otherwise affecting the interface to a subprogram. Depending on the situation, eliminating the non-null access check could reduce the overhead of a small function, without requiring the recompilation headaches associated with inlining. C) Scope checking We have not described what are the rules for using 'ACCESS on a parameter of mode "access," which will in turn determine the scope checking required at the call-site. The requirements for scope checking depend on the use. If the desire is to be able to pass local aliased variables to a function, then no scope check is desired at the call-site, implying that 'ACCESS on such a parameter should be treated like 'ACCESS on a local variable, only being useful for creating an access value of a similarly local access type. If the desire is just to be able to get dispatching on access types, then 'ACCESS is not needed inside, and a scope check at the call-site would be OK, though not important. If the desire is to be able to reconstruct an access value inside the subprogram, then it is important that 'ACCESS be usable to recreate a value of an access type declared global to the subprogram. This implies either a compile-time scope check at the call-site, or a run-time scope check at the use of 'ACCESS. Thus far we have resisted run-time scope checks. However, for formal parameters, any compile-time scope check at the call-site would be wrong in some cases. Hence, in this case, it seems better to require a run-time scope check on 'ACCESS applied to a by-access formal. If the result access type is a "normal" access type rather than a "general" access type (see LSN on General Access Types), a "pool" check would also be required. There would be no scope check at the call-site, though, depending on the implementation, it might be necessary to pass additional information to indicate the scope/pool of the actual (again, see the LSN on general access types). SUMMARY By introducing the parameter mode access, we have provided the following capabilities: 1) Dispatching on access types for tagged types; 2) By-access parameter passing; 3) Ability to reconstruct a pointer inside a subprogram (with a run-time scope/pool check); 4) By-access passing of local aliased variables to subprograms. Our primary goals were (1) and (3). (2) and (4) are frills, but potentially useful if not the source of undo complexity of understanding or implementation. Comments/Simplifications/Flames/etc welcome... -Tuck ------------------------------------------ An UPDATE as of 10 Dec 91: The term "access" was felt to be confusing, because inside the subprogram the formal parameter denotes the designated object rather than the access value. Therefore, we have reverted to the term "aliased" but now it is a parameter *mode* rather than a parameter *modifier*. The "aliased" mode means the same thing as the "access" proposed above, namely "X : aliased T" matches any access-to-T and any aliased T. We have also proposed that this parameter mode be usable with discriminants and functions. -Tuck ========================