Version 1.7 of ais/ai-00104.txt

Unformatted version of ais/ai-00104.txt version 1.7
Other versions for file ais/ai-00104.txt

!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)
Replace the paragraph:
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.
by:
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.
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
A useful test of these attributes is difficult to construct. Probably the most useful test would be a pair of C-Tests which check that the version values change when a "semantically significant" change is made. There is not currently an ACATS test checking this.
!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


****************************************************************

Questions? Ask the ACAA Technical Agent