!standard E.3 (05) 99-09-15 AI95-00104/08 !class binding interpretation 95-10-21 !status Corrigendum 2000 99-05-25 !status WG9 Approved 97-11-14 !status ARG approved 8-0-1 (subject to editorial review) 97-04-11 !status ARG approved 12-0-0 (subject to editorial review) 96-10-07 !status work item (letter ballot was 7-4-1) 96-10-03 !status ARG approved 7-0-1 (subject to letter ballot) 96-06-17 !status work item 96-04-04 !status received 95-10-21 !priority High !difficulty Hard !qualifier Clarification !subject Version and Body_Version attributes !summary If P is not a library unit, and P has no completion, then P'Body_Version returns the Body_Version of the innermost program unit enclosing the declaration of P. If P is a library unit, and P has no completion (which can be detected at compile time), then P'Body_Version returns a value that is different from Body_Version of any version of P that has a completion. E.3(5) is replaced with: The version of a compilation unit changes whenever the compilation unit changes in a semantically significant way. This International Standard does not define the exact meaning of "semantically significant". It is also unspecified whether there are other events (such as recompilation) that result in the version of a compilation unit changing. !question Two questions: E.3(4) says: P'Body_Version Yields a value of the predefined type String that identifies the version of the compilation unit that contains the body (but not any subunits) of the program unit. What if the program unit has no body? E.3(5) says: The version of a compilation unit changes whenever the version changes for any compilation unit on which it depends semantically. The version also changes whenever the compilation unit itself changes in a semantically significant way. It is implementation defined whether there are other events (such as recompilation) that result in the version of a compilation unit changing. First of all, it is not clear what "semantically significant" means. Second of all, the "implementation defined" part seems to leave a huge loophole; an implementation could change the version on every clock tick (at run time), which would mean the Version and Body_Version attributes would return a different value every time, which would make them useless. What is the intent? !recommendation (See summary.) !wording (See summary.) !discussion It should not be an error to query P'Body_Version when P has no body, because: 1. The purpose of P'Body_Version is to distinguish different implementations of P. If P has a body, that is a different implementation of P than if P does not have a body. P'Body_Version should return a different value in those two cases, not give an error. The client cares whether the implementation of P has changed; the client should not have to know whether or not that implementation involves a body. 2. The "error" is not detectable at compile time, in general. In particular, if P is not a library unit, one cannot tell from the declaration of P whether or not it has a body. The summary uses the term "completion" to account for the fact that there might be a pragma Import instead of a body. As to the second question, we choose to leave "semantically significant" vague, and trust implementations to do something sensible. The version should not change at the drop of a hat; in any given implementation, there should at least be some way of ensuring that execution of identical source code produces an identical version at run time. Some sensible implementations are: - The "traditional" (Ada 83) program library model: It would make sense for the version to be a time stamp representing the time of compilation. If the programmer recompiles a compilation unit, it will get a new version. The mechanism for ensuring identical versions is, "Don't recompile it". - A "source-based" model: The version is a combination of the time stamp of the source of the compilation unit itself, plus all compilation units upon which it depends semantically. If the compiler can guarantee that the same source always produces the same object code, which is usual, then the version could change if and only if the user edits the source files (whether or not any changes were actually made). The mechanism for ensuring identical versions is, "Don't edit the source files". - An optimization of the source-based model: The version is a "hash value" calculated from the source code of the compilation unit itself, plus all compilation units upon which it depends semantically. Comments are deleted before calculating the hash value. The mechanism for ensuring identical versions is, "Don't edit the source files, except to modify comments." - A different optimization: The last 20 versions of every file are remembered by the implementation. If the current version is identical to one of the remembered ones, then it gets the same version. Otherwise, it gets a new version. We don't want to require that identical source code always produces identical versions at run time. However, an implementation should provide *some* way of producing identical versions at run time when the source code hasn't changed. All of the above-mentioned possible implementations have this property. One can imagine much more sophisticated mechanisms, and we don't want to forbid them. In any case, it seems reasonable that if the object code changes, the version should change. We state this "only" as advice, because the International Standard has no formal concept of object code. In particular, there is no standard way of knowing which pieces of object code belong to which compilation units. The intent is that if the user does something semantically neutral, like adding a comment, then an implementation should be *allowed* to keep the version the same. In order to facilitate such "smart recompilation" strategies, we remove the phrase "implementation defined" from E.3(5), so that implementations need not document the exact cases when the version changes. Note that we remove the wording, "The version of a compilation unit changes whenever the version changes for any compilation unit on which it depends semantically." from E.3(5), because a compiler might be able to prove that whatever change was made to the compilation unit on which it depends semantically is irrelevant. In summary, in our view, the version of a compilation unit should change when its generated code changes. The version of a compilation unit should change when the version changes for a compilation unit upon which it depends semantically, if the change has a semantically significant effect on the first compilation unit. There may be other situations that also cause the version to change, but the implementation should provide a way to ensure that the version does not change if the compilation unit and the compilation units upon which it depends semantically do not change. Note that if X is a renaming declaration (not a renaming-as-body), then X'Version and X'Body_Version refer to the versions of the renamed entities. !corrigendum E.03(05) @drepl The @i of a compilation unit changes whenever the version changes for any compilation unit on which it depends semantically. The version also changes whenever the compilation unit itself changes in a semantically significant way. It is implementation defined whether there are other events (such as recompilation) that result in the version of a compilation unit changing. @dby The @i of a compilation unit changes whenever the compilation unit changes in a semantically significant way. This International Standard does not define the exact meaning of "semantically significant". It is also unspecified whether there are other events (such as recompilation) that result in the version of a compilation unit changing. If P is not a library unit, and P has no completion, then P'Body_Version returns the Body_Version of the innermost program unit enclosing the declaration of P. If P is a library unit, and P has no completion, then P'Body_Version returns a value that is different from Body_Version of any version of P that has a completion. !ACATS test Create a C-Test to check that P'Version changes when P changes in a semantically significant way. Check that when P does not have a completion, P'Body_Version returns a value different than the value returned by a version of P that has a completion. (No Test, 2-4-2, ARG Letter Ballot, February 2001). This cannot be tested with a single test. Following is a possible test methodology: Test 1: Compile a spec and body for a package P. Compile and link a main program that retrieves P'Version and P'Body_Version, and stores them in a file. (Prints "Tenatively passed") Test 2: Compile different specs and bodies for the package P. Compile and link a main program that retrieves P'Version and P'Body_Version, and compares them with the stored values. The test fails if they are the same. Note that this would be much more complex than existing ACATS tests, and its unclear that it would catch many errors. (And the vagueness of "semantically significant" would open such a test to challenges.) !appendix !section E.3(04) !subject P'Body_Version for package with no body !reference RM95-E.3(4) !from Keith Thompson 95-10-20 !reference 95-5358.a Keith Thompson 95-10-20>> !discussion The attribute P'Body_Version yields "a value of the predefined type String that identifies the version of the compilation unit that contains the body (but not any subunits) of the program unit." What should P'Body_Version yield for a package with no body? **************************************************************** !section E.3(04) !subject P'Body_Version for package with no body !reference RM95-E.3(4) !reference as: 95-5358.a Keith Thompson 95-10-20 !from Anthony Gargaro 95-10-22 !reference 95-5361.a Anthony 95-10-22>> !discussion > What should P'Body_Version yield for a package with no body? My understanding is that this should result in a compile-time error. **************************************************************** !section E.3(04) !subject P'Body_Version for package with no body !reference RM95-E.3(4) !reference as: 95-5358.a Keith Thompson 95-10-20 !reference 95-5361.a Anthony 95-10-22 !from Bob Duff !reference 95-5364.a Robert A Duff 95-10-23>> !discussion > > What should P'Body_Version yield for a package with no body? > > My understanding is that this should result in a compile-time error. Unfortunately, that doesn't always work. One cannot, in general, tell at compile time whether P has a body. Note that P can be any program unit, not necessarily a library unit. Also, I would think that a compile time error would make the feature less useful. I want to write code that uses P'Body_Version to check whether I've got the right implementation of P -- I don't care whether it has a body or not. If it changes from having a body to not having one, or vice-versa, then I want to be told it's a different version. How about the following rule: If P is not a library unit, and P has no body, then P'Body_Version returns the Body_Version of the innermost containing program unit. If P is a library unit, and P has no body [which can be detected at compile time], then P'Body_Version returns a value that is different from Body_Version of any version of P that has a body. Does this make sense? Is it reasonable to implement? - Bob **************************************************************** !section E.3(04) !subject P'Body_Version for package with no body !reference RM95-E.3(4) !reference 95-5358.a Keith Thompson 95-10-20 !reference 95-5361.a Anthony 95-10-22 !reference 95-5364.a Bob Duff 95-10-23 !reference 95-5365.a Anthony 95-10-23>> !discussion >> > What should P'Body_Version yield for a package with no body? >> >> My understanding is that this should result in a compile-time error. > Unfortunately, that doesn't always work. One cannot, in general, tell > at compile time whether P has a body. Note that P can be any program > unit, not necessarily a library unit. Thanks. I failed to note that interesting detail. > How about the following rule: > If P is not a library unit, and P has no body, then P'Body_Version > returns the Body_Version of the innermost containing program unit. I assume you intend the icpu where a body may be declared. > If P is a library unit, and P has no body [which can be detected > at compile time], then P'Body_Version returns a value that is > different from Body_Version of any version of P that has a body. Given the above rule this is not unreasonable. Presumably, an implementation can return a null string. I think it would be difficult to justify a compile-time error here. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(5) !from Ron Theriault 96-02-19 !keywords version consistency !reference 96-5427.a Ron J Theriault 96-2-19>> !discussion E.3(1) implies that the consistency of a distributed system be verified by means of the P'Version attribute, but does not require it. The wording of E.3(5) is sufficiently vague as to allow an implementation of P'Version which is useless for verifying the consistency of a distributed system. For instance, the wording of E.3(5) does not forbid the value of P'Version from being dependent on the clock time when the compiler generates a stub from the compilation unit where P is declared, assuming the unit is an RCI package. Unless the stubs are produced at the exact same instant, the values returned for P'Version will be different in the calling and receiving stubs. The following interpretation of E.3(5) will ensure that P'Version is usable for the purpose implied for it by E.3(1). E.3(5) shall be interpreted as follows: When discussing the implementation of P'Version, and P'Body_Version, "declaring unit" refers to the compilation unit that contains the declaration of P, and "body unit" refers to the compilation unit that contains the body (but not any subunits) of P. The value of P'Version changes whenever the declaring unit changes in a semantically significant way. The value of P'Version also changes whenever any compilation unit on which the declaring unit depends, changes in a semantically significant way. The value of P'Body_Version changes whenever the body unit changes in a semantically significant way. The value of P'Body_Version also changes whenever any compilation unit on which the body unit depends, changes in a semantically significant way. It is implementation defined whether there are other events which depend on the body unit (such as recompilation), which result in the value of P'Body_Version of the body unit changing. If there are such events, they must be fully documented by the implementor. Adept Project Texas A&M Univ. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(5) !reference 96-5427.a Ron J Theriault 96-2-19 !from Robert Dewar 96-02-26 !keywords version consistency !reference 96-5430.a Robert Dewar 96-2-26>> !discussion Ron suggests E.3(5) shall be interpreted as follows: When discussing the implementation of P'Version, and P'Body_Version, "declaring unit" refers to the compilation unit that contains the declaration of P, and "body unit" refers to the compilation unit that contains the body (but not any subunits) of P. The value of P'Version changes whenever the declaring unit changes in a semantically significant way. The value of P'Version also changes whenever any compilation unit on which the declaring unit depends, changes in a semantically significant way. The value of P'Body_Version changes whenever the body unit changes in a semantically significant way. The value of P'Body_Version also changes whenever any compilation unit on which the body unit depends, changes in a semantically significant way. It is implementation defined whether there are other events which depend on the body unit (such as recompilation), which result in the value of P'Body_Version of the body unit changing. If there are such events, they must be fully documented by the implementor. I don't think this is tenable. The notion of a "semantically significant change" is one that cannot possibly be defined. Indeed, the idea that version might not change when the package changes seems (though possibly desirable) contradictary to the current rules. This is a side issue (allowing such freedom) that I agree the ARG should address. Also, the wording above seems to suggest magic changes that happen as a result of changing other units (editing the source? compiling the other unit?) Remember that the original model here is that compilation time would be used as the version identifier (at one time the attribute was called something closer to compilation time, or certainly mentioned compilation time). If you think of a conventional Ada-83 style library system, and then think of using compilation time (of the spec for P'Version, and of the body for P'Body_Version). This is EXACTLY what is needed. Now the issue is to duplicate that for source based library systems like GNAT, and the obvious translation is that the version depends on the set of source files (e.g. time stamps) of relevant depended-on units. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(5) !from Ron Theriault 96-02-19 !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28>> !discussion The recommendation of Ada Issues note ai-00104 unfortunately, seems to duck the issue by relying on the implementor to "do something sensible". What is worse, is that no mention is made of the usability of P'Version for the purpose of verifying the consistency of a distributed program. P'Version is defined in Annex E! As a case in point, early releases of the GNAT compiler, produced values for P'Version which were not usable for consistency checking. The algorithm used then, was not inconsistent with the RM, nor would it be inconsistent with the isolated phrase "something sensible". Note 00104 further states: "The implementation must document the cases under which the version changes ... so the user can be aware of any unreasonable behavior on the part of an implementation." Not only does this sentence seem to contradict the earlier requirement to do "something sensible", but also it is cold comfort for a user who expects behavior for P'Version different from that of the implementor. Our experience has shown that the kind of information properly embodied in a value of P'Version is difficult to obtain outside of the context of a compiler. The Ada RM should rise above the kind of wishful thinking exhibited by this recommendation. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !from Bob Duff !reference 96-5583.a Robert A Duff 96-5-29>> !discussion > The recommendation of Ada Issues note ai-00104 unfortunately, > seems to duck the issue by relying on the implementor to > "do something sensible". What is worse, is that no mention is > made of the usability of P'Version for the purpose of verifying > the consistency of a distributed program. P'Version is defined > in Annex E! During the design of Ada 9X, we intentionally left this point vague, because we didn't know how to do better. When I wrote the draft version of AI-00104, I *still* didn't know how to do better, and thus left the definition vague. It does indeed "duck the issue". If you wish to insist on a more precise definition, it would be helpful if you could produce some suggested wording to replace E.3(5). You did suggest something in comment 96-5427.a, but there are some problems with that wording. Robert Dewar points out some problems in 96-5430.a (although he says, "The notion of a 'semantically significant change' is one that cannot possibly be defined," which can be taken equally as a criticism of E.3(5), since it uses that term). The main problem with the wording suggested in 96-5427.a, I think, is that it implies that (for specs) the version changes if and only if there is a semantically significant change. Now we haven't defined what "semantically significant change" means, but whatever definition we can come up with, it is going to be undecidable to determine. E.3(5) escapes the undecidability by saying that the version changes if there's a semantically significant change, but also in other implementation-defined cases. The compiler can say, for example, that the version changes whenever the source code is edited (since we know that if you don't edit the source, there is no semantically significant change, whereas if you *do* edit the source, there *might* be a semantically significant change). The wording in 96-5427.a, on the other hand, requires the compiler to detect that the user has made a semantically insignificant change, which is clearly impossible. So, do you have another wording suggestion? (Note that the ARG will be considering this AI at its next meeting in a couple of weeks, so please send your comments as soon as possible.) > As a case in point, early releases of the GNAT compiler, produced > values for P'Version which were not usable for consistency checking. > The algorithm used then, was not inconsistent with the RM, nor would > it be inconsistent with the isolated phrase "something sensible". It would also be helpful if you (or perhaps Robert Dewar) could describe the old GNAT implementation, and why it was unacceptable, and the new implementation, and why it is acceptable. It's not clear to me how you can say that the old implementation was "not usable...", and yet *was* "something sensible" -- sounds contradictory. In any case, it sounds like the AI's (and RM's) notion of "trusting implementations to do something sensible" worked just fine -- you complained about GNAT's implementation, and they fixed it. So why does the ARG need to make a ruling that defines things more precisely? Is there really a danger that users and implementers will disagree on what is "sensible" (for a given implementation)? > Note 00104 further states: "The implementation must document the cases > under which the version changes ... so the user can be aware of any > unreasonable behavior on the part of an implementation." > > Not only does this sentence seem to contradict the earlier requirement > to do "something sensible", The idea is simply that if we require implementations to document what they do, then they will be embarrassed to do something totally ridiculous. It's like, "We can trust presidential candidates not to use 4-letter words in public, because if they do, everybody will know about it, and the candidate will be embarrassed." :-) >... but also it is cold comfort for a user who > expects behavior for P'Version different from that of the implementor. Indeed. Can you give a code example of something that P'Version ought to be able to do, but that implementers don't necessarily agree with? Something a "real" implementer really might do (as opposed to an implementer that intentionally does what customers don't want). > Our experience has shown that the kind of information properly embodied > in a value of P'Version is difficult to obtain outside of the context > of a compiler. > > The Ada RM should rise above the kind of wishful thinking exhibited > by this recommendation. I have sympathy for this point of view, but so far, I don't know how to achieve it. In a private conversation, Tucker and I were both asked to define "semantically significant change". We came up with two different definitions. My definition was based on run-time semantics -- if the run-time semantics of the program changes, then that's semantically significant. Tucker's definition, on the other hand, included the Static Semantic sections of the RM -- i.e. if you make a change to the text of a program that causes an identifier X to change from denoting one thing to a different thing, then that's a semantically significant change, even if the compiler can prove that it makes no difference at run-time. Instead of trying to resolve that difference of opinion, I chose to leave the definition of "semantically significant change" vague, as it is in the RM. Note that the disagreement between Tucker and me is quite theoretical -- we don't really have compilers that prove such fancy things. My own opinion is that if the generated code changes, the version should change. (I didn't say "if and only if" -- the compiler doesn't generally know whether the generated code changed. The compiler can distinguish two cases (1) the generated code did not change, and (2) the generated code *might* have changed.) In any case, this rule can't be stated formally, since the RM has no notion of "generated code". I could tolerate a ruling along these lines: Implementation Advice The version should change if the generated code changes. The implementation should provide some mechanism to avoid changing the code, and also avoid changing the version. For example, the implementation might say, "If you don't type the compile command on X, then I promise not to change the generated code for X, and I promise not to change X'Version." A different implementation might say, "If you don't edit the source, or if you edit only comments and white-space, then ...[same promise]". I don't like the above, because it's "merely" Impl Advice (uses "should" instead of "shall"). Therefore, in practise, it's no better than simply admonishing one's compiler vendor to "do something sensible". On the other hand, if there's really a disagreement on what "sensible" means, informally, then perhaps some Impl Advice is in order. Implementation Advice is the only place where we're allowed to talk about "generated code". Chapter 10 of the RM has been re-written for Ada 95 to be very flexible, and I think that's important. (The Ada 83 rules were either meaningless, or overly restrictive, depending on how you interpret them.) An implementation ought to be allowed to do whatever it likes in terms of how-do-you-compile-things, and so forth. Any rule that tries to define when versions change needs to take this into account. For example, it would be silly to say "if you don't recompile X, then X'Version won't change", because the *implementation* defines when and how X gets recompiled -- it might be automatic. For any given compilation model, I can write a precise definition of versions that would satisfy you, but since the RM doesn't define the compilation model, I don't see how to define versions in general. Consider the rule that says the actual parameters of a procedure call are evaluated in an arbitrary order. Well, any sensible compiler will pick an order based on ease of implementation and/or efficiency. But suppose Compiler A reads the clock (at compile time), and generates a different order depending on whether it's Tuesday or not. Suppose Compiler B generates code that reads the clock (at run time), and chooses a different order based on whether it's Tuesday or not. In my opinion, Compiler A ought to use a different 'Version on Tuesdays, than the same source compiled on Wednesday, since the generated code changes. Compiler B is generating the same code, and so could reasonably (in my opinion) use the same 'Version. But this is just my opinion about particular (weird) implementations -- as far as the RM is concerned, Compiler A and Compiler B are identical. A final point: The RM doesn't define *everything*. We trust compilers to be reasonably fast, but the RM doesn't say anything about it. We trust compilers to produce sensible error messages, but the RM would allow an implementation to simply print "Illegal compilation unit" as its only error message, without even telling you which line of code it doesn't like. In my opinion, it would be "unreasonable" for a compiler to require me to type 99 keystrokes to invoke a compilation, but the RM doesn't forbid that. These are all cases where we rely on compiler writers to be "sensible". Since the 'Version attribute is intimately related to the compilation model, and we trust compilers to have a reasonable compilation model (without *requiring* that), then it seems that we will also have to trust compilers to produce a reasonable value for 'Version. Summary: I'm sympathetic to the idea that 'Version should be more precisely defined. But, I don't see how to do that, given the freedom that Ada 95 allows in compilation models. - Bob **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !from Ron Theriault !reference 96-5583.a>> !discussion My apologies for the delay in responding ... I have been at the JavaOne conference :-). > Bob Duff wrote [edited for brevity]: > If you wish to insist on a more precise definition, it would be helpful > if you could produce some suggested wording to replace E.3(5). You did > suggest something in comment 96-5427.a, but there are some problems with > that wording. Robert Dewar points out some problems in 96-5430.a > (although he says, "The notion of a 'semantically significant change' is > one that cannot possibly be defined," which can be taken equally as a > criticism of E.3(5), since it uses that term). Since there is so much difficulty in defining 'semantically significant change', I suggest that a different tack be taken in defining P'Version. Something along the following lines can be stipulated: "If the defining unit of P has a body, then the value of P'Version shall not depend on it. If the defining unit of P is an RCI, then the value of P'Version shall not change when stubs are produced for the defining unit, not shall it change when these stubs are compiled." > It would also be helpful if you (or perhaps Robert Dewar) could describe > the old GNAT implementation, and why it was unacceptable, and the new > implementation, and why it is acceptable. It's not clear to me how you > can say that the old implementation was "not usable...", and yet *was* > "something sensible" -- sounds contradictory. Apparently GNAT used to use P'Version for some purpose other than verifying the consistency of a distributed program. For that purpose, it apparently behaved "sensibly". You will have to consult the Gnat people for more details. > In any case, it sounds like the AI's (and RM's) notion of "trusting > implementations to do something sensible" worked just fine -- you > complained about GNAT's implementation, and they fixed it. So why does > the ARG need to make a ruling that defines things more precisely? Is > there really a danger that users and implementers will disagree on what > is "sensible" (for a given implementation)? Not exactly. GNAT was not changed until I submitted my comment on the Ada language specification. Coincidence? > Can you give a code example of something that P'Version ought > to be able to do, but that implementers don't necessarily agree with? The problem is that the phrase "something sensible" does not refer to distributed programs in any way! An implementation could use P'Version to assist in some optimization strategy, define an elegant behavior for P'Version to accomplish this goal, and document it precisely. This could be called a "sensible" implementation. The RM should stipulate that P'Version be usable for verifying the consistency of a distributed program. The implementor must document how P'Version can be used to verify the consistency of a distributed program. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !from Bob Duff !reference 96-5583.a>> !discussion > Since there is so much difficulty in defining 'semantically significant > change', I suggest that a different tack be taken in defining P'Version. > Something along the following lines can be stipulated: > > "If the defining unit of P has a body, then the value of P'Version > shall not depend on it. If the defining unit of P is an RCI, then > the value of P'Version shall not change when stubs are produced > for the defining unit, not shall it change when these stubs are > compiled." I assume by "defining unit" you mean "innermost enclosing library unit, or the library unit itself". (There are lots of "units" in Ada -- program units, compilation units, library units.) I don't see how the above wording can work. The RM does not define "when stubs are produced for the defining unit", or "when these stubs are compiled". I can understand what these terms mean in the GNAT implementation, but in RM terms, they seem meaningless. > Apparently GNAT used to use P'Version for some purpose other than > verifying the consistency of a distributed program. For that purpose, > it apparently behaved "sensibly". I'm not sure what you mean. E.3(6) defines *one* notion of consistency, and the implementation is required to detect that without using any Version attributes or anything else. The implementation will raise an exception or, at the very least, refuse to let inconsistent partitions communicate with each other. Clearly, if 'Version is to be useful for ensuring consistency, then that notion of consistency must go beyond what the RM already checks. I could imagine a stronger notion of consistency that took remote access types into account. Or took some other communication mechanism into account (some message-passing system that is totally outside the mechanisms defined by the RM). So what's *your* notion of consistency? >...You will have to consult the Gnat > people for more details. OK, GNAT people, what's up here? I'm confused. What did GNAT do before, and what does GNAT now do? And why are these bad and good, respectively? > Not exactly. GNAT was not changed until I submitted my comment on the > Ada language specification. Coincidence? Well, OK, but is this just a gripe with the GNAT implementation, or is it really a language issue? The RM isn't supposed to know things about how or when GNAT generates stubs. > > Can you give a code example of something that P'Version ought > > to be able to do, but that implementers don't necessarily agree with? > > The problem is that the phrase "something sensible" does not refer > to distributed programs in any way! An implementation could use > P'Version to assist in some optimization strategy, define an > elegant behavior for P'Version to accomplish this goal, and document > it precisely. This could be called a "sensible" implementation. I agree that "sensible" ought to mean "sensible for the intended purpose." > The RM should stipulate that P'Version be usable for verifying the > consistency of a distributed program. The implementor must document how > P'Version can be used to verify the consistency of a distributed program. If we don't define "consistency", then we can't "stipulate" anything about it. We can say "P'Version *should* be usable for verifying consistency", and we can require documentation as you suggest. But I'm not sure that solves your problem. "Should" is always a huge loophole. I asked for a "code example", above. I really think that might help me (and others) understand what the problem is, here. (I apologize if I'm being dense, but I honestly don't understand the problem, other than that you didn't like what GNAT did at some time in the past, and now they've fixed it.) - Bob **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !reference 96-5583.a Bob Duff !from Ron Theriault !reference 96-5583.a>> !discussion > Bob Duff: > > RT: > > "If the defining unit of P has a body, then the value of P'Version > > shall not depend on it. If the defining unit of P is an RCI, then > > the value of P'Version shall not change when stubs are produced > > for the defining unit, not shall it change when these stubs are > > compiled." > > I assume by "defining unit" you mean "innermost enclosing library unit, > or the library unit itself". (There are lots of "units" in Ada -- > program units, compilation units, library units.) I mean the compilation unit that contains the declaration of P. > I'm not sure what you mean. E.3(6) defines *one* notion of consistency, > and the implementation is required to detect that without using any > Version attributes or anything else. ... Maybe you do not interpret the use of the word 'version' in E.3(6), as indicating the value returned by P'Version for the 'library unit' in E.3(6). However I think it is sensible to do so, in which case, the P'Version value evaluated in one partition, will match the P'Version value of the same unit evaluated in another partition. > I asked for a "code example", above. I really think that might help me > (and others) understand what the problem is, here. (I apologize if I'm > being dense, but I honestly don't understand the problem, other than > that you didn't like what GNAT did at some time in the past, and now > they've fixed it.) We use the following code (not the GNAT implementation) to check consistency of two partitions of a distributed program. It is executed on any partition which may execute a remote call to RCI package "mplot", before control is passed to the application program. The receiving stub for "mplot" registers the P'Version value of itself with a central server when it elaborates. "RCI_Name_Server.Lookup" fetches this value from the central server, and blocks until it is available: if RCI_Name_Server.Lookup ("mplot") /= mplot'Version then Put_Line (Standard_Error, "mplot is inconsistent: registered=" & RCI_Name_Server.Lookup ("mplot") & " expected=" & mplot'Version); raise Program_Error; end if; In the previous version of GNAT which I did not think was reasonable, the above test always failed. (There was no sequence of compilation linking, and/or editing operations I know of, which would cause it to succeed.) **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !from Robert Dewar !reference 96-5593.a Robert Dewar 96-6-5>> !discussion Ron said Not exactly. GNAT was not changed until I submitted my comment on the Ada language specification. Coincidence? Absolutely, definitely a coincidence. In fact our trouble was that we could not understand what Ron was talking about, once we understood, the issue was a simple bug in GNAT, nothing to do with any issues of intent or design. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !from Ron Theriault !reference 96-5583.a>> !discussion After the preceeding discussions, I submit the following updated wording for consideration as clarification of E.3(05): "If two partitions of a distributed program are consistent, P'Version will evaluate to the same value in both partitions, for all P which are visible to both partitions. If two partitions of a distributed program are not consistent, P'Version will evaluate to different values in each partition, for at least one P which is visible to both partitions." **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !from Robert Dewar !reference 96-5600.a Robert Dewar 96-6-11>> !discussion Ron said After the preceeding discussions, I submit the following updated wording for consideration as clarification of E.3(05): "If two partitions of a distributed program are consistent, P'Version will evaluate to the same value in both partitions, for all P which are visible to both partitions. If two partitions of a distributed program are not consistent, P'Version will evaluate to different values in each partition, for at least one P which is visible to both partitions." I find this wording risky. Suppose we recompile the spec, does the mere act of recompilation make the spec inconsistent with a previous version even though nothing has changed. As long as the answer to this is a clear and unambiguous yes, all is well. Basically two models for version must work. In one, you use the time stamp of the compilation, which records the object in some persistent library. The other uses an identification of the sources. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !reference 96-5600.a Robert Dewar 96-6-11 !from Erhard Ploedereder 96-6-20 !reference 96-5604.a Erhard Ploedereder 96-6-20>> !discussion Robert writes: > Basically two models for version must work. In one, you use the time stamp > of the compilation, which records the object in some persistent library. > The other uses an identification of the sources. I disagree on the second alternative without substantive clarification. The 'Version of a unit, whose source has not changed, nevertheless must not remain unchanged, if the unit has a semantically significant dependency on a changed unit. On the first alternative (while acceptable) there should be a clarifying provision that a (re)compilation yielding identical code need not alter the 'Version value. **************************************************************** !section E.3(05) !subject P'Version ambiguity !reference RM95-E.3(05) !keywords version consistency !reference 96-5578.a Ron J Theriault 96-5-28 !reference 96-5583.a Ron Theriault !reference 96-5600.a Robert Dewar 96-6-11 !reference 96-5604.a Erhard Ploedereder 96-6-20 !from Robert Dewar 96-6-21 !reference 96-5608.a Robert Dewar 96-6-21>> !discussion Erhard writes: >>Robert writes: >> Basically two models for version must work. In one, you use the time stamp >> of the compilation, which records the object in some persistent library. >> The other uses an identification of the sources. > >I disagree on the second alternative without substantive clarification. >The 'Version of a unit, whose source has not changed, nevertheless must >not remain unchanged, if the unit has a semantically significant dependency >on a changed unit. Well of course, the "sources" in question must include the sources of all units involving semantically significant dependencies (at least, in general, as in GNAT, it is likely that insignificant dependencies, e.g. unused withs, will also be included). That's required to meet the RM semantics. I did not feel the need to make this clarification originally, since that point seems uncontroversial. The issue I was concentrating on was the use of source time stamps as the information source. >On the first alternative (while acceptable) there should be a clarifying >provision that a (re)compilation yielding identical code need not alter >the 'Version value. Sure, just as in the second alternative, you need not alter the 'Version value if no semantically significant change to the sources has occurred. Actually I do not think you can talk about "identical code", since that is a meaningless concept. I think you have to talk about semantically equivalent code (almost as meaningless, but we already introduced some such concept!) **************************************************************** !section E.3(04) !subject Version and Body_Version attributes !reference AI95-00104/01 !from Norman Cohen !reference 96-5689.a Norman H. Cohen 96-9-6>> !discussion I have no problem with the recommendation, but the !discussion needs editorial work. The paragraph beginning "As to the second question," is incoherent. I don't understand the closing parenthetical comment; I can't even parse it. There is an apparent contradiction between that paragraph, which says that identical source code should produce an identical version, and the subsequent paragraph, which states that in the traditional program-library model, recompiling the same source produces a new version. If the first of these two paragraphs is meant to say that not recompiling source code IS A WAY OF ENSURING that identical source code produces identical versions, I don't understand the meaning of "produce", nor the meaning of "identical" (which generally implies a comparison among two or more entities). **************************************************************** !section E.3(06) !subject 'Version and 'Body_Version attributes !reference RM95-E.3(6) !reference AI-95-00104 !from Bob Duff !reference 96-5772.a Robert A Duff 96-11-24>> !discussion Samuel Tardieu said: > These attributes are vital for our implementation of the distributed > systems annex: the different partitions of a distributed system may be > built on different systems at different times; then how do you make > sure that the partition you are calling did use the same spec than the > one you used at compilation time? > > In our case, versions are used to ensure that we have a global > consistency. Since we have several executables which may have been > bound and linked separately from each other, we cannot rely on a > binder to check the consistency as this is the case in a single > executable model. The consistency is then checked at elaboration time > using these attributes. This sounds like a violation of E.3(6). If the implementation does E.3(6) properly, then the elaboration-time checks can't fail, it seems to me. If E.3(6) is undesirable for some reason, then that's a much bigger problem. Surely there are (ought to be?) ACVC tests for E.3(6)? > Offer> P.S. I wonder if 'Partition_Version would not have been a much > Offer> more useful and simpler solution... > > I don't think so for the reasons explained above: we need a per > package information, since we don't know a priori what will reside in > a partition (and in our model, we don't even know at compile time > which partition the remote units we are using will be on). OK, for 'Version, but 'Body_Version is not currently defined to be "per package". E.g. if a subunit of a package changes, then 'Body_Version of the package does not. But how is the client supposed to know whether the package has subunits? Laurent Pautet says: > Let's say that Compression_Method is a normal unit (replicated > on two partitions P1 with RCI_1 and P2 with RCI_2) with the > same specification on both sides. > > On RCI_1 > > if Compression_Method'Body_Version = > RCI_2.Get_Your_Compression_Body_Version then > RCI_2.RPC_Using_Compressed_Image > (Compression_Method.Apply (Image); > else > RCI_2.RPC_Using_Regular_Image (Image); > end if; OK, but the author of this code doesn't (shouldn't) know how Compression_Method is implemented. Maybe Compression_Method calls Compression_Method_Subroutine to do most of its work. If Compression_Method_Subroutine is in another package, then when Compression_Method_Subroutine changes, the above code won't notice. To be useful, shouldn't X'Body_Version change whenever anything that X can call changes? Or maybe just local calls, and not remote calls to some third partition? > Don't except too much from the partitioning/configuration > tool. Version consistency checks have to be performed during > execution. Otherwise, they are useless. > > If partitions are built by two different compilers vendors, first, > they should check consistency by calling `Version; second, `Version > has to be precisely defined such a way that the two implementations > return the same string. Annex E doesn't have much to say about different compilers. It assumes a single compiler. I think it tries to avoid getting in the way of using multiple compilers, but it doesn't try to have any specific support for that scenario. It doesn't come anywhere near supporting what you say above -- to do that, we would have to define the exact form of version strings. Otherwise, there can be no requirement that two different compilers will return the same string for the same source code. (E.g. one compiler might return a compilation time-stamp, and another compiler might use a hash-code on the source text (with or without comments, etc).) > Offer Pazy wrote : > | It seems to me that you have to ensure that the function > | Get_Your_Compression_Method must always return the a value consistent with > | the attribute value. This may be specially tricky when the said body > | indirectly depends on other things in RCI_2 (just as the value of some > | variable which may be set by another, completely unrelated unit, in RCI_2). > > True, so what? Compression_Method unit is different, the client is not > sure that the server compression is *exactly* the same and will send > the regular image. But, given the current definition of 'Body_Version in the RM (and in AI-104), there is no way for the client to know that it is not *exactly* the same. > BTW, it is Get_Your_Compression_Body_Version (not > ... *Compression_Method) just because Compression_Method is a normal > replicated package. If Compression_Method'Body_Version was invoked, > you would get the body version of the local unitt and not the one of > the remote unit. Get_Your_Compression_Body_Version is just a remote > call to Compresson_Mehtod'Body_Version. So of course, the returned > value is definitively consistent with the attribute. Yes, I understand that. Anyway, I'm left confused. People say these attributes are "essential" for distributed programming, but I can't see how the current definitions of their semantics is at all helpful for distributed programming. How do people deal with these issues when they write distributed programs in other languages (e.g. C)? - Bob ****************************************************************