Version 1.1 of ais/ai-00035.txt

Unformatted version of ais/ai-00035.txt version 1.1
Other versions for file ais/ai-00035.txt

!standard 07.03.01 (07)          96-11-16 AI95-00035/03
!class confirmation 95-06-25
!status WG9 approved 96-12-07
!status ARG approved 12-0-0 96-10-07
!status ARG approved 5-0-3 (subject to editorial review) 96-06-17
!status work item 95-06-25
!status received 95-06-25
!priority Medium
!difficulty Medium
!subject Type descriptors can be laid out at compile time
!summary 95-06-25
Implementation Note: It is possible (and desirable) for an implementation to allocate and initialize type descriptors statically.
!question 96-09-15
The rules in 7.3.1 imply that for a type declared in a package_declaration, certain inherited subprograms can be declared in the package_body. How does this correspond to the intended implementation model of AARM-3.9(1.a-1.b)?
1.a The intended implementation model is for a tag to be represented as a pointer to a statically allocated and link-time initialized type descriptor. The type descriptor contains the address of the code for each primitive operation of the type. It probably also contains other information, such as might make membership tests convenient and efficient.
1.b The primitive operations of a tagged type are known at its first freezing point; the type descriptor is laid out at that point. It contains linker symbols for each primitive operation; the linker fills in the actual addresses.
!response 95-06-25
Although the inherited subprogram might be declared in the package_body, the fact that it is going to be declared there is known at compile time of the package_declaration. Thus, there is no conflict with the above-mentioned implementation model.
!appendix

!section 7.3.1(7)
!subject overriding in body
!reference AARM-7.3.1(7p);6.0
!from Jesper Joergensen 95-04-05
!reference as: 95-5115.a Jesper Joergensen 95-4-5>>
!discussion

Until yesterday we thought that 3.9.2(13) "the explicit declaration of a
primitive subprogram of a tagged type shall occur before the type is frozen..."
ensured that we could build the dispatch table for a tagged type declared in a
package specification based upon information from the package specification
alone. It seems, however, that there are cases where we need information from
the corresponding package body.

Consider a modification of the example in 7.3.1(7d-7k):


package Parent is
   type Root is tagged null record;
private
   procedure Op2( X : Root );   -- private primitive for Root
end Parent;


package Parent.Child is
   package Nested is
      type T4 is new Root with null record;
      -- T4 inherits Op2, but Op2 isn't declared until the body
   private
      procedure Op2( X : T4 );   -- overrides, BUT NOT YET
   end Nested;
private
   -- nothing interesting happens to Op2 here
end Parent.Child;


package body Parent.Child is
   package body Nested is
      -- Here the derived Op2 gets declared and immediately overridden.
      -- That means that the explicit Op2 overrides the inherited also in the
      -- dispatch table for T4!?
      procedure Op2( X : T4 ) is
      begin
         null;
      end Op2;
   end Nested;
end Parent.Child;


Since the explicitly declared Op2 overrides the implicitly declared one,
3.9.2(20) says that the body to execute for a call on T4's Op2 is that in the
body of Nested. Was this the intention and doesn't it violate the second
principle of 3.9.2(13a) and make 3.9.2(13d) = false?

Of course, you could say that from the package specification alone we can see
that when the body for Nested comes, there will be an overriding, but it needs
a twist in the code to implement this.

Or am I missing some rule that prevents an overriding to happen in the body?


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

!section 7.3.1(7)
!subject overriding in body
!reference AARM-7.3.1(7p);6.0
!reference 95-5115.a Jesper Joergensen 95-04-05
!from Tucker Taft 95-04-06
!reference as: 95-5117.a Tucker Taft 95-4-6>>
!discussion

> Until yesterday we thought that 3.9.2(13) "the explicit declaration of a
> primitive subprogram of a tagged type shall occur before
> ... the type is frozen..."
> ensured that we could build the dispatch table for a tagged type declared in a
> package specification based upon information from the package specification
> alone. It seems, however, that there are cases where we need information from
> the corresponding package body.

Your example below is correct.  However, there is no "information" coming
from the package body.  It just happens to be the place where the
implicit declaration (which is overridden by the earlier explicit
declaration) occurs.

> Consider a modification of the example in 7.3.1(7d-7k):
>
>
> package Parent is
>    type Root is tagged null record;
> private
>    procedure Op2( X : Root );   -- private primitive for Root
> end Parent;
>
>
> package Parent.Child is
>    package Nested is
>       type T4 is new Root with null record;
>       -- T4 inherits Op2, but Op2 isn't declared until the body
>    private
>       procedure Op2( X : T4 );   -- overrides, BUT NOT YET
>    end Nested;
> private
>    -- nothing interesting happens to Op2 here
> end Parent.Child;
>
>
> package body Parent.Child is
>    package body Nested is
>       -- Here the derived Op2 gets declared and immediately overridden.
>       -- That means that the explicit Op2 overrides the inherited also in the
>       -- dispatch table for T4!?
>       procedure Op2( X : T4 ) is
>       begin
>          null;
>       end Op2;
>    end Nested;
> end Parent.Child;
>
>
> Since the explicitly declared Op2 overrides the implicitly declared one,
> 3.9.2(20) says that the body to execute for a call on T4's Op2 is that in the
> body of Nested. Was this the intention and doesn't it violate the second
> principle of 3.9.2(13a) and make 3.9.2(13d) = false?

This was the intent.  It doesn't violate the second principle of 3.9.2(13b),
nor make 3.9.2(13e) false, [are you using an older version of the AARM?],
because the link-name of the overriding Op2 is known at the time the type
descriptor needs to be built.

> Of course, you could say that from the package specification alone we can see
> that when the body for Nested comes, there will be an overriding, but it needs
> a twist in the code to implement this.

Perhaps, but this "twist" is necessary to correctly implement
the semantics.  The expected implementation was that at the point of
the derivation, all primitives that would eventually be inherited will
be identified by the compiler.  Their implicit declarations might be
postponed, but the compiler needs to know what primitives "exist" and
will "eventually" be declared to make appropriate choices about
which "dispatching slot" to assign to each explicitly declared primitive
subprogram.

> Or am I missing some rule that prevents an overriding to happen in the body?

The overriding doesn't really "happen" in the body.  The implicit
declaration, wherever it occurs, is overridden by the explicit declaration
(which must be in the spec somewhere if the tagged type declaration is).

-Tuck

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

!section 7.3.1(7)
!subject overriding in body
!reference AARM-7.3.1(7p);6.0
!reference 95-5115.a Jesper Joergensen 95-04-05
!reference 95-5116.a Tucker Taft 95-04-06
!reference as: 95-5118.a Jesper Joergensen 95-4-7>>
!discussion
>
> This was the intent.  It doesn't violate the second principle of 3.9.2(13b),
> nor make 3.9.2(13e) false, [are you using an older version of the AARM?],

No, sorry, I use 6.0 but I made the citation wrong, it was supposed to read
"3.9.2(13d)".

> Perhaps, but this "twist" is necessary to correctly implement
> the semantics.  The expected implementation was that at the point of
> the derivation, all primitives that would eventually be inherited will
> be identified by the compiler.  Their implicit declarations might be
> postponed, but the compiler needs to know what primitives "exist" and
> will "eventually" be declared to make appropriate choices about
> which "dispatching slot" to assign to each explicitly declared primitive
> subprogram.
>
> The overriding doesn't really "happen" in the body.  The implicit
> declaration, wherever it occurs, is overridden by the explicit declaration
> (which must be in the spec somewhere if the tagged type declaration is).

Well, 8.3(9) defines overriding as a phenomenon between two *declarations*,
not between subprograms that just exist but are not declared. Therefore, I
will still claim that we can't talk about any overriding until both of the
declarations have actually taken place. In fact, we implemented the
registration of overriding in our visibility system: when a declaration is
made visible (implicitly or explicitly) a test for overriding is performed and
registrered. Now we need registration of an overriding outside the visibility
system before both declarations have been met.

But now on to the next question, the purpose of which is to show whether we
have understood things correctly. Consider the slightly more complicated
example:


package Parent is
   type Root is tagged null record;
private
   procedure Op2( X : Root );   -- private primitive for Root
end Parent;


package Parent.Child is
   package Nested is
      type T4 is new Root with null record;
      -- T4 inherits Op2, but Op2 isn't declared until the body
   private
      procedure Op2( X : T4 );   -- overrides, BUT NOT YET
      type T5 is new T4;         -- inherits both Op2's, the one inherited
                                 -- from that in the previous line is
                                 -- implicitly declared here, the other one
                                 -- is implicitly declared in the body
   end Nested;
private
   -- nothing interesting happens to Op2 here
end Parent.Child;


package body Parent.Child is
   package body Nested is
      -- Here a second inherited Op2 gets declared for T5 and because this one
      -- occurs later than the implicit declaration that occurred at the
      -- declaration of T5 itself, this one is overriding the previous one
      -- [8.3(12)] (no matter who overrides who for T4).
      procedure Op2( X : T4 ) is
      begin
         null;
      end Op2;
   end Nested;
end Parent.Child;

Isn't it surprising that the overriding subprogram of T5 is exactly the
overridden one for T4, i.e we dispatch to the same Op2 for Root and T5, but
for the intervening T4 we dispatch to the explicitly declared one. I would
have assumed that because T4 decides to override Op2, this overriding would
also count for its derivatives.

If, in the body Nested we derive T6 from T5, which of the inherited Op2's
win?

>
> -Tuck
>
/Jesper

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

!section 7.3.1(6)
!section 7.3.1(7)
!section 8.2(12)
!subject overriding in body
!reference AARM-7.3.1(6);6.0
!reference AARM-7.3.1(7p);6.0
!reference AARM-8.2(12);6.0
!reference 95-5115.a Jesper Joergensen 95-04-05
!reference 95-5116.a Tucker Taft 95-04-06
!reference 95-5118.a Jesper Joergensen 95-4-7
!from Tucker Taft 95-04-12
!reference as: 95-5126.a Tucker Taft 95-4-12>>
!discussion

> ...
> But now on to the next question, the purpose of which is to show whether we
> have understood things correctly. Consider the slightly more complicated
> example:
>
>
> package Parent is
>    type Root is tagged null record;
> private
>    procedure Op2( X : Root );   -- private primitive for Root
> end Parent;
>
>
> package Parent.Child is
>    package Nested is
>       type T4 is new Root with null record;
>       -- T4 inherits Op2, but Op2 isn't declared until the body
>    private
>       procedure Op2( X : T4 );   -- overrides, BUT NOT YET
>       type T5 is new T4;         -- inherits both Op2's, the one inherited
>                                  -- from that in the previous line is
>                                  -- implicitly declared here, the other one
>                                  -- is implicitly declared in the body
>    end Nested;
> private
>    -- nothing interesting happens to Op2 here
> end Parent.Child;
>
>
> package body Parent.Child is
>    package body Nested is
>       -- Here a second inherited Op2 gets declared for T5 and because this one
>       -- occurs later than the implicit declaration that occurred at the
>       -- declaration of T5 itself, this one is overriding the previous one
>       -- [8.3(12)] (no matter who overrides who for T4).

This was not the intent.  The Op2 inherited by T4 from Root
is never visible, since it is overridden at its declaration,
and hence is hidden from all visibility throughout its scope.
Per 7.3.1(6), this overridden Op2 is never declared for T5,
since it is never visible.

>       procedure Op2( X : T4 ) is
>       begin
>          null;
>       end Op2;
>    end Nested;
> end Parent.Child;
>
> Isn't it surprising that the overriding subprogram of T5 is exactly the
> overridden one for T4, i.e we dispatch to the same Op2 for Root and T5, but
> for the intervening T4 we dispatch to the explicitly declared one. I would
> have assumed that because T4 decides to override Op2, this overriding would
> also count for its derivatives.

The overriding is intended to apply to the derivatives.  Perhaps the words
could be more explicit, but the basic idea is that since T4's
overridden Op2 is never visible, it is never declared for T5.

> If, in the body Nested we derive T6 from T5, which of the inherited Op2's
> win?

T4, T5, and T6 would all share the same implementation of Op2.

> /Jesper

-Tuck

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

Questions? Ask the ACAA Technical Agent