!standard 8.3(12) 04-06-02 AC95-00099/01 !standard 8.3(13) !standard 8.3(26/1) !class confirmation 04-06-02 !status received no action 04-06-02 !status received 04-05-04 !subject Possible hole related to AI83-00012 !summary !appendix !topic Possible hole related to AI83-00012 !reference RM95 3.4(17,23),7.3.1(6),8.3(12,13),12.3(16) !from Adam Beneschan 04-05-04 !discussion The following is based on AI83-00012: generic type T1 is private; type T2 is private; package GP3 is type T is range 1..10; procedure PROC (X : T1; Y : T); procedure PROC (Z : T2; Y : T); end GP3; package P3 is new GP3 (INTEGER, INTEGER); type NT is new P3.T; X1 : P3.T; X2 : NT; begin P3.PROC (X => 5, Y => X1); -- legal? P3.PROC (Z => 5, Y => X1); -- legal? PROC (X => 5, Y => X2); -- legal? PROC (Z => 5, Y => X2); -- legal? This AI discusses what happens when instantiation and/or derived types result in the creation of two subprograms that are homographs. In the above case, when the instance P3 is created, it will contain two PROC procedures that are homographs---both with Integer as the first parameter and P3.T as the second---but this is allowed by AI83-00012 and explicitly allowed by RM95 8.3(26). Both PROC's are primitive subprograms of T. The wording of 8.3(13) appears to make these subprograms "implicitly declared". Later, when NT is derived, both primitive operations are inherited, so there are two versions of PROC whose first parameter has type Integer and whose second parameter has type NT. They are homographs, and they are implicit. In both cases (the two PROC's in P3, and the two inherited PROC's declared for NT), we have two implicit subprograms that are homographs. Question: Does 8.3(12) [which was not part of Ada 83 or AI83-00012] kick in? This says "An implicit declaration of an inherited subprogram overrides a previous implicit declaration of an inherited subprogram". But is one of them "previous"? For the first case, 8.3(13) says "These new declarations occur immediately after the type declaration", but says nothing about what order they're declared in, if any. Similarly, 3.4(23) says that the inherited subprograms are both declared "immediately after the derived_type_definition", but there's nothing there that says what order they're declared in. This looks like an omission to me; the RM should say something about this. It seems that one of these should be true: (1) When more than one inherited subprogram is declared at the same place (in 3.4(23) and 7.3.1(6)), the subprograms are declared in the same order as they are for the parent type. This would mean that the PROC that takes X as a parameter is overridden by the one that takes Z as a parameter, by 8.3(12), and thus the first call to PROC is illegal while the second is legal. If this is the case, the RM should say so explicitly. A similar rule needs to be present for the "whole new set of primitive subprograms" in 8.3(13) and/or 12.3(16), although I'm not sure how it would be worded. (2) When more than one inherited subprogram is declared at the same place, none of those subprograms is considered previous to any other, so that 8.3(12) does not apply to any two of those subprograms. A similar rule would need to be in 8.3(13) and/or 12.3(16). For what it's worth, some of the wording in AI83-00012 seemed to indicate that any of the homographs should be callable; for a slightly more complicated case involving a second generic, the AI says: (Note that if it is legal, one of the homographs can be called by writing P4.PROC(X => ...).) and I'm sure the author intended this to apply equally to the procedure whose first parameter is named Z. **************************************************************** From: Randy Brukardt Sent: Wednesday, June 2, 2004 9:17 PM The wording changes for AI-251 (interface types) have the side effect of making examples like this illegal. (At least, the author of the AI makes this claim; I'm not quite certain about this -- it doesn't appear that the Ada 95 situation is changed to me -- but I don't see why this would be legal in Ada 95, either. The definition of homographs that neither override nor hide is illegal by 8.3(26/1).) Given that the examples are illegal, there isn't any need to figure out what they mean. The rest of Adam's note makes it clear that we don't want to have to figure that out! **************************************************************** From: Tucker Taft Sent: Wednesday, June 2, 2004 10:03 PM > The wording changes for AI-251 (interface types) have the side effect of > making examples like this illegal. (At least, the author of the AI makes > this claim; I'm not quite certain about this -- it doesn't appear that the > Ada 95 situation is changed to me -- but I don't see why this would be legal > in Ada 95, either. The definition of homographs that neither override nor > hide is illegal by 8.3(26/1).) I don't see why Randy thinks this is illegal in Ada 95 or Ada 2000. I can believe that AI-251 will make it illegal in Ada 200Y. In Ada 2000, clearly the instantiation is legal. The derived type is a more interesting question, but it seems to be legal as well, presuming one believes the implicit declarations of inherited subprograms occur in some order, since the latter implicit declaration will override the earlier one, by 8.3(12). In any case, there is no part of 8.3(26/1) that makes an overridable declaration illegal, and clearly both inherited subprograms of type NT are "overridable." > Given that the examples are illegal, there isn't any need to figure out what > they mean. The rest of Adam's note makes it clear that we don't want to have > to figure that out! I would say most of the example is legal. If we believe that the "second" implicit declaration overrides the first implicit declaration, then the Proc with formal params X and Y for type NT is overridden by the Proc with formal params Z and Y. I think the subtle order dependence here is one reason why AI-251 wants to make the derived type illegal. **************************************************************** From: Randy Brukardt Sent: Wednesday, June 2, 2004 10:23 PM > I don't see why Randy thinks this is illegal in Ada 95 or Ada 2000. > I can believe that AI-251 will make it illegal in Ada 200Y. > In Ada 2000, clearly the instantiation is legal. I must have missed something. 12.3(11) says that legality rules are rechecked in the visible part of an instance. 8.3(26/1) is a legality rule. Neither of the two explictly declared PROCs are overriddable. In the instance, we have: procedure PROC (X : Integer; Y : T); procedure PROC (Z : Integer; Y : T); which clearly are illegal homographs by 8.3(26/1). What did I miss?? **************************************************************** From: Pascal Leroy Sent: Thursday, June 3, 2004 1:21 AM > I must have missed something. > 12.3(11) says that legality rules are rechecked in the visible part of an > instance. 8.3(26/1) is a legality rule. Neither of the two explictly > declared PROCs are overriddable. In the instance, we have: > procedure PROC (X : Integer; Y : T); > procedure PROC (Z : Integer; Y : T); > which clearly are illegal homographs by 8.3(26/1). What did I miss?? I think you missed the last sentence of 8.3(26/1), which says that all the rules in this paragraph don't apply in an instance. In other words, I agree with Tucker that the instantiation was legal in Ada 95+TC1. I also believe that the type derivation was legal, although the language was quite muddled here, since as Adam pointed out you don't quite know what operation(s) you get. The fact that AI 251 makes the type derivation illegal seems like a good thing in this perspective. **************************************************************** From: Randy Brukardt Sent: Thursday, June 3, 2004 5:44 PM I apparently had a complete brain lock -- I never saw the derived type in either AI-251 or the Adam's questions, and never realized that it was being talked about, not the instantiations. Sigh. In any case, I think we've proven that Adam's problem is taken care of by Ada 200Y -- which is the important point, because it means we don't have to decide how it works. **************************************************************** From: Adam Beneschan Sent: Thursday, June 3, 2004 6:54 PM No, I think we were talking about both. My original example did ask about two separate but similar cases: homographs created by an instantiation, and homographs created by type derivation. The instantiation case seems to be legal in Ada 95 because 8.3(26/1) says that the rules don't apply in an instance. The derived type case hasn't been discussed as much, but Tucker explained why he thought it was legal in Ada 95. In any case, the change to 8.3(26/1) proposed by AI-251 does make the derived type case illegal. After looking at this more closely, I think I blew it when discussing the instantiation case. I cited 8.3(12), but that rule applies only to inherited subprograms, and there weren't any in my example (looking at just the instantiation). Here's another case: generic type T1 is private; type T2 is private; package GP3 is type T is range 1..10; procedure PROC (X : T1; Y : T); procedure PROC (Z : T2; Y : T); type NT is new T; end GP3; package P3 is new GP3 (INTEGER, INTEGER); Now, when P3 is created, these inherited subprograms are created inside P3: procedure PROC (X : INTEGER; Y : NT); procedure PROC (Z : INTEGER; Y : NT); AI-251 doesn't make this illegal because the last sentence of the proposed replacement for 8.3(26/1) still means that the rule doesn't apply in an instance, when the operations aren't dispatching. So I think in this case, my question seems to remain unanswered: in the instance P3, does one of the inherited PROC procedures in the instance override the other (by 8.3(12)) even though they weren't homographs in the generic? Or do we say neither one is considered "previous" to the other, for the purposes of 8.3(12)? **************************************************************** From: Randy Brukardt Sent: Thursday, June 3, 2004 7:59 PM I would be very opposed to even trying to answer this question, because of the likelyhood of causing unintended consequences from fiddling with the homograph rules. (AI-251 is bad enough.) That's especially true because this is really bad code piled on bad code. Deriving user routines for an untagged type is almost always a mistake and unintended -- I'd prefer that doing so was illegal (but that would be too incompatible). Similarly, the only reason that these instantiations are allowed in the first place is compatibility with Ada 83 (Ada 83 didn't really have checks for legal instantiations, so this was allowed; Ada 95 has a better model of checking, and there is no reason that this couldn't be detected). So I'd prefer to repeal the last sentence of 8.3(26/1) -- but again, that won't fly because of compatibility reasons. Given that this code is junk, whatever a compiler does is fine -- there's no portability issue with junk code. If the programmer insists on pointing a bazooka at their foot, they shouldn't be surprised if their foot disappears. The ARG has better things to do than determine which foot they blow away. **************************************************************** From: Michael F. Yoder Sent: Saturday, June 5, 2004 1:46 PM I considered ignoring this on the basis that it's just a difference of opinion, but after all I think it's worth objecting: the claim is incorrect. Why on earth should deriving from an untagged type be bad, but deriving from a tagged type be good? Deriving from any such type is at least as likely to be using strong typing for what it's intended, as to be an error. I've written code that looked much like the above; the old and new types were time types, and it was important to distinguish them because one was meant to be monotonic and the other not. (The package in question, though, didn't have any potential homograph problems that I recall.) As far as the instantiation is concerned, as a user I'm reluctant to endorse a rule that makes instantiations illegal if they cause homographs; and I'd much prefer when one operation overrides another, that which is victorious be constant across implementations. But I could probably live with a regime that mandated using a new type, derived from Integer, to instantiate with two types structurally identical to Integer in the above case. **************************************************************** From: Randy Brukardt Sent: Saturday, June 5, 2004 4:41 PM I wasn't referring to derivation per-se, but deriving with primitive subprograms. Those can be dangerous, because they have many bad properties: they re-emerge in generics, they prevent the use of rep. clauses on the derived type, etc. None of the bad properties apply to tagged types (as Tucker likes to say, they work "right"). Every time that I've derived primitive subprograms of an untagged type, it has been unintentional; I would have rather that the subprograms weren't derived at all. **************************************************************** From: Nick Roberts Sent: Saturday, June 5, 2004 9:07 PM > I wasn't referring to derivation per-se, but deriving with primitive > subprograms. That seems like a weird statement, frankly. When does one ever derive a type that has no primitive operations? > Those can be dangerous, because they have many bad properties: > they re-emerge in generics, Isn't there an amendment proposal to rectify this problem? > they prevent the use of rep. clauses on the derived type, This restriction could conceivably be repealed. > etc. Well, what is the "etc.", please? > None of the bad properties apply to tagged types (as Tucker likes > to say, they work "right"). > > Every time that I've derived primitive subprograms of an untagged > type, it has been unintentional; I would have rather that the > subprograms weren't derived at all. Does that include declarations such as: type T is range A..B; which are, of course, also a kind of derivation? Take a look at the OMG IDL mapping for Ada, Randy. It's stuffed with non-tagged type derivations, as is just about any big software 'layer' or binding in Ada. They are a major language tool, very far from being dispensible or mistaken. **************************************************************** From: Randy Brukardt Sent: Monday, June 7, 2004 3:13 PM > That seems like a weird statement, frankly. When does one ever derive a type > that has no primitive operations? I was referring to user-defined privitive operations, of course. Predefined primitives aren't interesting. > > Those can be dangerous, because they have many bad properties: > > they re-emerge in generics, > > Isn't there an amendment proposal to rectify this problem? No, it was determined to be too incompatible. There are actually programs which depend on re-emergence. (Which seems to me to be doubling the error, but whatever.) > > they prevent the use of rep. clauses on the derived type, > > This restriction could conceivably be repealed. I've tried. There is a strong feeling that there should not be expensive conversions implicitly occurring in calls. (Janus/Ada actually supported this; we missed the rule that makes it illegal for years.) ... > > Every time that I've derived primitive subprograms of an untagged > > type, it has been unintentional; I would have rather that the > > subprograms weren't derived at all. > > Does that include declarations such as: > > type T is range A..B; > > which are, of course, also a kind of derivation? Of course not; this isn't a "derived type declaration", which only can happen via a "derived_type_declaration" (i.e. "new"). And in any case, I was only talking about user-defined subprograms (they're the only ones with that bad properties mentioned above), and certainly this doesn't have any. ****************************************************************