!standard 13.3.2(9/3) 10-11-16 AI05-0230-1/02 !class Amendment 10-10-25 !status Amendment 2012 10-11-16 !status ARG Approved 10-0-0 10-10-30 !status work item 10-10-25 !status received 10-10-25 !priority Low !difficulty Easy !subject Inheritance of null procedures with preconditions !summary Pre and Post aspects may not be specified for null procedures (Pre'Class and Post'Class may be used). !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 (See wording.) !wording Modify 13.3.2(9/3) [added by AI05-0145-2]: The Pre or Post aspect shall not be specified for an abstract subprogram {or a null procedure}. [Redundant: Only the Pre'Class and Post'Class aspects may be specified for such a subprogram.] !discussion We could try to allow Pre and Post on concrete null procedures and give such subprograms preference over those inherited from interfaces. But since a null procedure doesn't do anything, we can't quite imagine what the Pre and Post aspects would be useful for. One example was suggested (to prevent calls) seems to be pushing to runtime a check that ought to be done at compile-time (by declaring the subprogram abstract). Since the uses are mostly hacks, we decide that it isn't worth the effort to allow these ever. We don't know of any other 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. !corrigendum 13.3.2(0) @dinsc For a subprogram or entry, the following language-defined aspects may be specified with an @fa: [Just to force a conflict, the real text will be in the conflict file.] !ACATS test An ACATS B-Test is needed. !ASIS There is no ASIS effect to this rule. !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"? ****************************************************************