!standard 3.3.1(10) 10-10-25 AI05-0230-1/01 !standard 3.3.1(21) !class Amendment 10-10-25 !status work item 10-10-25 !status received 10-10-25 !priority Low !difficulty Easy !subject Inheritance of null procedures with preconditions !summary (See proposal.) !problem There is a problem with pre- and post-conditions (ignoring those which are unconditionally True) on null procedures because RM 8.3(12.3/2) assumes that null procedures with the same profile are interchangeable. Thus it would be possible to inherit two null procedures with different Pre or Post aspects. Which one is executed then? !proposal !wording AI 05-00145 already includes a (not yet numbered) paragraph beginng with The Pre or Post aspect shall not be specified for an abstract subprogram. Add the following to the end of that paragraph: The Pre or Post aspect shall not be specified for a primitive subprogram of an interface type. Replace 8.3(12.2/2) If at least one is a subprogram that is neither a null procedure nor an abstract subprogram, and does not require overriding (see 3.9.3), then they override those that are null procedures, abstract subprograms, or require overriding. If more than one such homograph remains that is not thus overridden, then they are all hidden from all visibility. with An ineffective procedure is defined to be a null procedure which is a primitive operation of an interface type, or an inherited subprogram which corresponds (see 3.4) to an ineffective procedure. If at least one is a subprogram that is neither an ineffective procedure nor an abstract subprogram, and does not require overriding (see 3.9.3), then they override those that are ineffective procedures, abstract subprograms, or require overriding. If more than one such homograph remains that is not thus overridden, then they are all hidden from all visibility. We should probably also replace the two occurrences of "null procedure" in the next paragraph with "ineffective procedure", but this isn't strictly needed. !discussion Are there more cases where we use some mechanism (e.g., a pragma or an aspect specification) to cause implicit code generation for a subprogram. pragma No_Return is forbidden for a null procedure and an Invariant aspect specification is illegal for an abstract type (which includes interface types), so these are not problems. !discussion !ACATS test !appendix From: Steve Baird Sent: Thursday, October 21, 2010 5:56 PM I think there may be a problem with pre- and post-conditions (ignoring those which are unconditionally True) on null procedures because RM 8.3(12.3/2) assumes that null procedures with the same profile are interchangeable. Perhaps contracts should be forbidden for null procedures which are primitive subprograms of interface types and 8.2 could be modified to prefer a not-really-null-because-it-has-a-nontrivial-contract null procedure over other null procedures. Does it seem clear that there is a problem here? Would an example be useful? Does the proposed solution seem reasonable? **************************************************************** From: Randy Brukardt Sent: Thursday, October 21, 2010 6:10 PM I don't think that banning contracts on certain interfaces is the right way to go. That just says "if you want to use interfaces, you can't use contracts". There is already way too much that you can't do with interfaces, it would be silly to make them even worse. Besides, the same problem can happen if an abstract routine of an interface has a contract and a null procedure of a different interface has a contract. Doesn't the AI already handle the case of multiple contracts from inherited routines (it would seem like it would have to do that)? **************************************************************** From: Steve Baird Sent: Thursday, October 21, 2010 6:25 PM > ... > > I don't think that banning contracts on certain interfaces is the > right way to go. That just says "if you want to use interfaces, you > can't use contracts". There is already way too much that you can't do > with interfaces, it would be silly to make them even worse. Contracts and interface types play well together using the Pre'Class and Post'Class aspects, but those are not what I am talking about. I'm talking about the Pre and Post aspects. > Besides, the same problem can happen if an abstract routine of an > interface has a contract and a null procedure of a different interface has a contract. > Doesn't the AI already handle the case of multiple contracts from > inherited routines (it would seem like it would have to do that)? We have a legality rule in the Ai: The Pre or Post aspect shall not be specified for an abstract subprogram. Only the Pre'Class and Post'Class aspects may be specified for such a subprogram. I am suggesting that this restriction be generalized to also apply to any primitive subprogram of an interface type. **************************************************************** From: Randy Brukardt Sent: Thursday, October 21, 2010 6:42 PM OK, that makes sense. (I wonder why that wasn't true in the first place??) **************************************************************** From: Edmond Schonberg Sent: Friday, October 22, 2010 10:25 AM > Does it seem clear that there is a problem here? > Would an example be useful? > Does the proposed solution seem reasonable? I should mention that we've had one customer who asked for preconditions on null procedures. The justification was rather bogus: the precondition was False, to ensure that any descendants would be forced to override the operation in question. For this purpose it would have been simpler to make the procedure abstract. The customer request came before Pre'Class was introduced, so this would be the proper way to do it now. I agree with Steve's proposal to forbid Pre and Post on primitives of interfaces, whether they are abstract or null. **************************************************************** From: Yannick Moy Sent: Friday, October 22, 2010 10:52 AM The thing is you cannot have an abstract procedure on a non-abstract type, right? So if you want to have already some common components shared in the root type, you have to make the procedure null rather than abstract. Or is there an idiom to avoid this? **************************************************************** From: Edmond Schonberg Sent: Friday, October 22, 2010 11:17 AM Yes of course, if this is the addition of one primitive to legacy code, giving a False precondition to a new null primitive allows you to modify the descendant types incrementally. Everything continues to work as long as you don't call the primitive in question. If you make the new primitive abstract that forces you to touch all the descendant declarations. So Pre'Class => False is a reasonable condition for an ancestor null operation. **************************************************************** From: Tucker Taft Sent: Friday, October 22, 2010 11:29 AM I think the important point is we are talking about restricting use of "Pre" and "Post" rather than "Pre'Class" and "Post'Class." I think Pre'Class => False does just what you want, so there is no need for Pre => False. **************************************************************** From: Steve Baird Sent: Friday, October 22, 2010 11:45 AM An abstract type (as opposed to an interface type, which is one special kind of abstract type) may have components. So the idiom you are looking for, I think, is to use an abstract non-interface type. **************************************************************** From: Steve Baird Sent: Monday, October 25, 2010 12:12 PM Another case where a null procedure is not ineffective is if it is subject to an Invariant specification (indirectly, of course, since an Invariant specification applies to a type, not to a subprogram). We could extend the definition of ineffective to handle this case, but I just spent 5 minutes working on this approach and it seemed to be getting pretty verbose. And pragma No_Return might have easily introduced similar problems (it didn't, but the point is that we seem to have lots of constructs which cause implicit code to be generated for subprograms). So how about replacing the first paragraph above with An ineffective procedure is defined to be a null procedure which is a primitive operation of an interface type, or an inherited subprogram which corresponds (see 3.4) to an ineffective procedure. If we don't like the term "ineffective", then of course it could be replaced here and in the 2nd paragraph. Perhaps "strongly null"? ****************************************************************