!standard 04.06 (16) 04-09-22 AI95-00384/02 !class binding interpretation 04-09-09 !status Amendment 200Y 04-09-22 !status ARG Approved 9-0-0 04-09-18 !status work item 04-09-09 !status received 04-09-09 !priority Medium !difficulty Medium !subject Conversion rules should be symmetric !summary The legality rule in paragraph 4.6(16) for conversion between access-to-nontagged-discriminated types is not symmetric between the operand type and the target type. It should be changed to be symmetric by permitting conversion from an access-to-unconstrained object to an access-to-constrained type (with an appropriate run-time check on the conversion). !question Why is the legality rule in paragraph 4.6(16) assymmetric between the operand type and the target type? 4.6(50) already requires a run-time check to verify that the designated object satisfies the constraints of the target designated subtype, so there seems no reason to disallow at compile-time the conversion from an access-to-unconstrained to an access-to-constrained. Here is an example of the problem: procedure P is type T(B : Boolean) is record ... end record; type Acc_T is access all T; type Acc_T_True is access all T(True); X : Acc_T; Y : Acc_T_True; Z : Acc_T := Acc_T(Y); -- legal by 4.6(16) W : Acc_T_True := Acc_T_True(X); -- illegal by 4.6(16) procedure Loc(A : in Acc_T) is ... procedure Loc_Update(B : in out Acc_T) is ... begin Loc(Acc_T(Y)); -- legal by 4.6(16) Loc_Update(Acc_T(Y)); -- illegal by 4.6(16,24) ... end P; There seems no reason to make the conversion to Acc_T_True illegal above, since the run-time check specified by 4.6(50) would catch any problem. Similarly, because access values are passed by copy, there is already a run-time check on copy "out" for an IN OUT or OUT parameter, so there seems no reason to disallow the view conversion of Y to Acc_T. The combination of 4.6(24) and 4.6(16) currently makes that illegal. !recommendation (See summary.) !wording Change 4.6(16) as follows: ... and either the designated subtypes shall statically match or [the target] {one of the} designated subtype{s} shall be discriminated and unconstrained; ... AI-363 has a rewrite of this paragraph. It would be changed as follows: * If the target designated type is not tagged, then the designated types shall be the same, and either: - the designated subtypes shall statically match; or - the designated type shall be discriminated in its full view and unconstrained in any partial view, and [the target] {one of the} designated subtype{s} shall be unconstrained. !discussion Most of the legality rules for conversion between two types are symmetric. The few cases of assymmetry have to do with accessibility, or class-wide-ness. (And the class-wide-ness asymmetry is arguably also a mistake). This symmetry is useful because reverse conversions are implicit in conversions used as OUT or IN OUT parameters, and it is confusing if the illegality of the reverse conversion makes a view conversion illegal. For some reason, 4.6(16) has an asymmetric rule for conversion between access-to-untagged-discriminated types. The likely reason is to minimize the number of run-time checks associated with conversions. However, unlike the case with the class-wide conversion asymmetry, where a simple work-around is to convert first to a class-wide type and from there to a specific descendant, there is no way around 4.6(16). You simply can't get "there" from "here," when "there" is an access-to-constrained and "here" is an access-to-unconstrained. One conceivable concern might be the impact of changing 4.6(16) on an implementation of discriminated records where the discriminants are stored separate from the rest of the components. We don't know of any implementations which do this, but it has been suggested as a possible way to efficiently support physical units associated with numeric values. However, if you think about this implementation model, it seems more likely that 4.6(16) as written makes it harder rather than easier. For many current compilers, array bounds are stored separately from the array components, *except* for access-to-unconstrained array types. By storing them together in this case, the access-to-unconstrained array type can be represented by a single pointer. With this model, it is *easier* to convert from an access-to-unconstrained *to* an access-to-constrained. But this is the direction that 4.6(16) disallows. This would be true for separated discriminants as well. Converting *to* access-to-constrained would be easier than converting *from* access-to-constrained, since when converting from access-to-constrained to access-to-unconstrained, you need to somehow get the separated discriminants into the heap. This is one reason we prohibited converting an access-to-constrained-array into an access-to-unconstrained-array type. !corrigendum 4.6(16) @drepl @xbullet @dby @xbullet !ACATS test Create a C-Test to insure that these conversions are legal and checked at runtime. !appendix ****************************************************************