!standard 3.4(7/3) 15-01-22 AI05-0140-1/02 !standard 3.4(8/2) !class binding interpretation 14-10-13 !status work item 14-10-13 !status received 14-07-10 !priority Low !difficulty Medium !qualifier Omission !subject Access to unconstrained partial view when full view is constrained !summary The first subtype of a private type always statically matches the first subtype of the full view of the type. !question I have a following code which is accepted by GNAT and ICCAda, but rejected by Janus/Ada: with Ada.Unchecked_Deallocation; package UNC is type My_String (<>) is limited private; type My_String_Access is access My_String; private type My_String is new String; procedure Free is new Ada.Unchecked_Deallocation (My_String, My_String_Access); end UNC; -- end of example code Janus/Ada gives me an error: In File C:\work\unconstrained-constrained\unc.ads at line 10 -------------- 9: procedure Free is new 10: Ada.Unchecked_Deallocation (My_String, My_String_Access); ----------------------------------------------------^ *ERROR* Formal and actual must both be constrained or unconstrained (6.4.10) [RM 12.5.4(3)] The full view of My_String is constrained, while My_String_Access designates the partial view of My_String, which is unconstrained. The question is: Is the example code legal or not? (Yes.) !recommendation (See Summary.) !wording Add after 3.2(7): AARM Ramification: "Null constraint" includes the cases of no explicit constraint, as well as unknown discriminants and unconstrained array type declarations (which are explicit ways to declare no constraint). Add to 4.9.1(2/3): A subtype of a private type P that has a null constraint statically matches the first subtype of the full type of P. !discussion The vendor error message refers to 12.5.4(3): For a formal access-to-object type, the designated subtypes of the formal and actual types shall statically match. The text of the vendor error message (and the associated question) is wrong, as 3.7(26) says that "Any subtype of a type with unknown discriminants is an unconstrained and indefinite type." (This is repeated in 3.2(9) and 3.3(22/3).) So the private type My_String is unconstrained. Similarly, the full type My_String is unconstrained. However, it is unclear if the formal and actual types do in fact statically match in this case. First, it is true that My_String_Access designates a different view (and thus subtype) than the subtype denoted by My_String. The view designated by an access type does not change during the lifetime of the type. Thus we need to determine if the partial view and full view statically match in this case. [Editor's note: That's definitely true for incomplete views (see 3.10.1(2.2-2.6/3)). I can't find as clear an indication for partial views, but it would be nonsense for incomplete views to work completely differently than partial views. Most properties are "characteristics" of the type anyway; here we're concerned about matching of subtypes.] The important part of 4.9.1(2/3) is "A subtype statically matches another subtype of the same type if they have statically matching constraints..." (the rest is about predicates and access types, neither of which apply here). There is no exception for unconstrained subtypes here, so we have to match the constraints even in that case. Statically matching constraints is defined directly above. Clearly, none of the bullets 4.9.1(1.2-1.4/2) apply. Does 4.9.1(1.1/2)? (Careful: "null constraint" has nothing to do with "null exclusion"s.) A "null constraint" is understood to be the the lack of an explicit constraint. Again, it's clear that an unknown discriminant is not nothing; it's an explicit not-a-constraint. But wait! 3.2(7/2) gives a definition for "null constraint" (in parens, and oddly IMHO): "(the case of a null constraint that specifies no restriction is also included)". So does an unknown discriminant "specify no restriction"?? Surely, an unknown discriminant specifies something. Indeed, it specifies fewer restrictions than giving no constraint at all (as private types have to be completed with definite types unless unknown discriminants appear). So one could make a pedantic argument that a null constraint does not include no constraint at all, as even that puts requirements on the full types. Still, the Dewar rule would suggest that 3.2(7/2) needs to apply to unknown discriminants. After all, having the partial view not statically matching the full view of the same type would be annoying. We should at least add an AARM note explaining this case. However, this explanation leaves the author wondering. What if we had tried the example implied by the subject of this AI? That is: package UNC2 is type My_String (<>) is limited private; -- "null constraint" type My_String_Access is access My_String; private type My_String is new String(1..10); -- "index constraint" procedure Free is new Ada.Unchecked_Deallocation (My_String, My_String_Access); end UNC2; Now none of the 4 bullets in 4.9.1(1-1.4/2) are true (even assuming that unknown discriminants are a null constraint); the full view has an explicit constraint and the partial view has none. Ergo, the partial view and the full view don't statically match, and thus the instantiation should be illegal. However, every compiler that we tested this code on accepted it. (Even the compiler in the original question -- go figure! Perhaps there is an ACATS test requiring this to work.) There doesn't seem to be any justification for this. We can make this more explicit by writing out the subtypes: package UNC3 is type My_String (<>) is limited private; -- "null constraint" subtype My_String_P is My_String; type My_String_Access is access My_String_P; private type My_String is new String(1..10); -- "index constraint" subtype My_String_F is My_String; procedure Free is new Ada.Unchecked_Deallocation (My_String_F, My_String_Access); end UNC3; Here, there is no possible reason (given the current wording) for My_String_P and My_String_F to statically match: constraints are not a "characteristic" that appear for a private type. After all, this is essentially the same as type An_Array is array (Positive range <>) of Integer; subtype An_Array_P is An_Array; subtype Con_An_Array is An_Array(1..10); subtype An_Array_F is Con_An_Array; and we *know* An_Array_P and An_Array_F don't statically match. To fix this, we have to use the narrowest possible rule, because we surely don't want to allow anything beyond the minimum necessary. Thus, we've added a sentence saying that the subtype of a private type that has a null constraint always matches the first subtype of the full type. !ASIS No ASIS effect. !ACATS test We probably need an ACATS C-test like the example in the question. !appendix !topic Access to unconstrained partial view when full view is constrained !reference 12.5.4(3) !from Tero Koskinen 10-07-14 !keywords unconstrained constrained partial view !discussion I have a following code which is accepted by GNAT and ICCAda, but rejected by Janus/Ada: with Ada.Unchecked_Deallocation; package UNC is type My_String (<>) is limited private; type My_String_Access is access My_String; private type My_String is new String; procedure Free is new Ada.Unchecked_Deallocation (My_String, My_String_Access); end UNC; -- end of example code Janus/Ada gives me error: In File C:\work\unconstrained-constrained\unc.ads at line 10 -------------- 9: procedure Free is new 10: Ada.Unchecked_Deallocation (My_String, My_String_Access); ----------------------------------------------------^ *ERROR* Formal and actual must both be constrained or unconstrained (6.4.10) [RM 12.5.4(3)] Full view of My_String is constrained, while My_String_Access designates the partial view of My_String, which is unconstrained. The question is: Is the example code legal or not? PS. Originally found when compiling Adalog's debug package: http://www.adalog.fr/compo2.htm#Debug **************************************************************** From: Tucker Taft Sent: Friday, July 11, 2014 9:26 AM Your code is legal. Janus seems to be freezing the fact that the designated type of My_String_Access is unconstrained, rather than recomputing it based on visibility at the point of generic instantiation. The rule for static matching between the designated subtype of a formal and actual has nothing to do with where the access type is declared. **************************************************************** From: Randy Brukardt Sent: Monday, July 14, 2014 6:54 PM You don't give any justification for this position. I couldn't find any in the RM. I wouldn't expect a property of an access type to change over its life without some explicit wording for that. For a counter-example, access-to-incomplete types are always considered that during their full lifetime - that does not change because of visibility. We have special rules that say that they are treated as complete when the completion of the incomplete type is available. (See 3.10.1(2.2/2-2.6/3)). We've got rules defining that characteristics behave this way, but whether a type is constrained or not does not appear to be a characteristic -- at least its not mentioned in the list in 3.4(8/2). So I don't see any RM reason for your interpretation. Perhaps there is a usability one (although I think it would have to be fairly strong given the destruction of the model that types are defined by their definition, which we adhere to despite the often nonsense results that one gets). **************************************************************** From: Tucker Taft Sent: Monday, July 14, 2014 7:40 PM >> Your code is legal. Janus seems to be freezing the fact that the >> designated type of My_String_Access is unconstrained, rather than >> recomputing it based on visibility at the point of generic >> instantiation. The rule for static matching between the designated >> subtype of a formal and actual has nothing to do with where the >> access type is declared. > > You don't give any justification for this position. I couldn't find > any in the RM. I wouldn't expect a property of an access type to > change over its life without some explicit wording for that. But this is not a property of the access type, it is a property of the designated type. Furthermore, these are exactly the *same* type, so it is downright weird if they don't match each other statically. If you want other analogies, the properties of a composite type change when more information is learned about the component type. See 7.3(3/3). But my main claim is that this is not a property of the access type at all. It is a property of the designated type, and you can use whatever you know about the designated type, even if it is "more" than is known where the access type is declared. You mention access-to-incomplete -- that seems a perfect example of this. Anywhere you can see the completion of the incomplete type, you can use that information, no matter where the access-to-incomplete type is declared. Yes we have extra wording to that effect in 3.10.1(2.4), but that wording is not saying anything profound. We just had to be careful because of the oddities associated with limited with's. There are no such subtleties for other properties relating to designated types. > For a counter-example, access-to-incomplete types are always > considered that during their full lifetime - that does not change > because of visibility. We have special rules that say that they are > treated as complete when the completion of the incomplete type is available. > (See 3.10.1(2.2/2-2.6/3)). > > We've got rules defining that characteristics behave this way, but > whether a type is constrained or not does not appear to be a > characteristic -- at least its not mentioned in the list in 3.4(8/2). > > So I don't see any RM reason for your interpretation. Perhaps there is > a usability one (although I think it would have to be fairly strong > given the destruction of the model that types are defined by their > definition, which we adhere to despite the often nonsense results that one gets). Well it sounds like an AI would be helpful to clarify this, but for me you are inappropriately associating a property of the designated type with the access type. The properties of the designated type change as you learn more about the designated type. The particular access type involved is somewhat irrelevant, as far as I am concerned, and especially as far as static matching is concerned. **************************************************************** From: Randy Brukardt Sent: Monday, July 14, 2014 8:29 PM > But this is not a property of the access type, it is a property of the > designated type. > Furthermore, these are exactly the *same* type, so it is downright > weird if they don't match each other statically. They're the same type but different views of that type. They don't necessarily have to match (certainly different subtypes of a type don't have to match). But I do agree that a user would find it weird if they didn't match (this I hadn't previously noticed). > If you want other analogies, the properties of a composite type change > when more information is learned about the component type. See > 7.3(3/3). Um, that's the syntax for a private extension. You probably meant 7.3.1(3/3), which is of course the "characteristics" rule that I referred to. The problem being that whether or not a type is constrained doesn't appear to be a "characteristic" (these are defined in 3.4(8/2). Perhaps it should be. > But my main claim is that > this is not a property of the access type at all. It is a property of > the designated type, and you can use whatever you know about the > designated type, even if it is "more" than is known where the access > type is declared. Even if it is, it doesn't appear to be a "characteristic" that appears when you have more visibility. > You mention access-to-incomplete -- that seems a perfect example of > this. Anywhere you can see the completion of the incomplete type, you > can use that information, no matter where the access-to-incomplete > type is declared. Yes we have extra wording to that effect in > 3.10.1(2.4), but that wording is not saying anything profound. We > just had to be careful because of the oddities associated with limited > with's. > There are no such subtleties for other properties relating to > designated types. Harmph. You seem to have conveniently forgotten about all of the problems with "additional characteristics", especially in generics. I'd say there's a pile of subtleties for other properties (including which properties are in fact included). I know there's quite a pile of ACATS tests on these weird cases (and I'd probably be strung up by implementers if I created any more :-). ... > Well it sounds like an AI would be helpful to clarify this, but for me > you are inappropriately associating a property of the designated type > with the access type. The properties of the designated type change as > you learn more about the designated type. The particular access type > involved is somewhat irrelevant, as far as I am concerned, and > especially as far as static matching is concerned. It's pretty clear to me that we're statically matching the private view (which is what the access type designates) to the full view (which is what the generic has for an actual). The view designated by an access type never changes! The question is whether the "characteristics" (the only things that rely on visibility) include everything needed for static matching. It's certainly true that the private view has more characteristics at the point of this instance than it does at the point of the declaration of the access type, but does it have enough for static matching? Static matching is quite a bit tougher than simple type matching, after all. We could simply say that they statically match, but that seems dangerous if there is any way for a visibility hole to be involved (that is, a case where both the partial and full views are visible but the relationship between them is not visible). [I can't think of one off-hand, but there are so many ways to create those that I can't convince myself that it is impossible.] And of course we'd have to be careful that other subtypes don't get sucked into such a special rule. **************************************************************** From: Tucker Taft Sent: Friday, June 26, 2015 5:21 PM I believe we should add (something like) the following, somewhere or other in the standard, to resolve AI12-0140: The *designated subtype* of (a view of) an access type at a given point is determined by the view of the designated subtype that is visible at that point, except in the case where the designated subtype denoted an incomplete view at the point of the declaration of the access type, and the incomplete view was part of a limited view of a package. In that case, the designated subtype of (a view of) the access type remains this incomplete view at all points that are not within the scope of a nonlimited with clause for the package in which the type is declared. Within the scope of such a nonlimited with clause, the more general rule applies. **************************************************************** From: Tucker Taft Sent: Friday, June 26, 2015 5:27 PM This might allow us also to remove that complex wording relating to the type of a dereference of an access-to-incomplete type. **************************************************************** From: Bob Duff Sent: Friday, June 26, 2015 8:12 PM > The *designated subtype* of (a view of) an access type at a given > point is determined by the view of the designated subtype that is > visible at that point, except in the case where the designated subtype > denoted an incomplete view at the point of the declaration of the > access type, and the incomplete view was part of a limited view of a > package. In that case, the designated subtype of (a view of) the > access type remains this incomplete view at all points that are not > within the scope of a nonlimited with clause for the package in which the > type is declared. Within the scope of such a nonlimited with clause, the > more general rule applies. "place". **************************************************************** From: Randy Brukardt Sent: Wednesday, July 8, 2015 7:18 PM You mentioned this when we were discussing AI12-0003-1 (January 31, 2015); I researched it and found that there were 20 normative references to "at the place of" and more than 18 normative references to "at the point of" (I stopped counting at that point, er place ;-). As such, either is fine, and there doesn't seem to be anything to recommend one over the other. **************************************************************** From: Randy Brukardt Sent: Wednesday, July 8, 2015 7:51 PM > The *designated subtype* of (a view of) an access type at a given > point is determined by the view of the designated subtype that is > visible at that point, except in the case where the designated subtype > denoted an incomplete view at the point of the declaration of the > access type, and the incomplete view was part of a limited view of a > package. In that case, the designated subtype of (a view of) the > access type remains this incomplete view at all points that are not > within the scope of a nonlimited with clause for the package in which > the type is declared. Within the scope of such a nonlimited with > clause, the more general rule applies. I think this would make more sense if it talked about the "view of the designated subtype", since the designated subtype itself is surely determined solely by the declaration (as defined in 3.10(10)). And it seems to be a tautology that the designated subtype is determined by the view of the designated subtype (duh!), which is what it currently says. Maybe it would be better to start: The view of the designated subtype of (a view of) an access type at a given point is the view of the designated subtype that is visible at that point, except in the case ... I think we have to be clearer than "visible at that point"; I'm not sure what kind of visibility you're talking about here. I'd also worry that this sort of rule would introduce a ripple effect (after all, the reason that we have the complex incomplete rules is to avoid a ripple effect). Since this is intended to fix issues with static matching (coming from confusion about what view an access type uses), one could potentially get a ripple effect anywhere that static matching is required on a designated partial view. When we get a full proposal for this wording, I'll try to see if there is a problem there (it could be FUD). ****************************************************************