Version 1.3 of ais/ai-00117.txt

Unformatted version of ais/ai-00117.txt version 1.3
Other versions for file ais/ai-00117.txt

!standard 03.09.02 (10)          99-04-01 AI95-00117/04
!class binding interpretation 96-04-04
!status ARG Approved (with changes) 7-1-1 99-03-24
!status work item 96-04-04
!status received 96-04-04
!priority High
!difficulty Hard
!subject Calling Conventions
!summary
Unless specified otherwise in the RM, the default convention of any entity is Ada.
An inherited or overriding subprogram of a type extension inherits the calling convention of the parent subprogram.
New operations of type extensions have the convention of their type unless a new convention is defined for the operation, if this is supported by an implementation.
The convention of the partial view of a private type or private extension is the convention of the full type.
An explicitly declared dispatching operation shall not have convention Intrinsic. An implicitly declared dispatching "/=" operator with boolean result has convention Intrinsic, and this is legal.
!question
6.3.1 defines the default convention of various entities (that is, the convention in the absence of a convention-specifying pragma):
2 As explained in B.1, ``Interfacing Pragmas'', a convention can be specified for an entity. For a callable entity or access-to-subprogram type, the convention is called the calling convention. The following conventions are defined by the language:
3 The default calling convention for any subprogram not listed
below is Ada. A pragma Convention, Import, or Export may be used to override the default calling convention (see B.1).
4 The Intrinsic calling convention represents subprograms that are
``built in'' to the compiler. The default calling convention is Intrinsic for the following:
5 an enumeration literal;
6 a "/=" operator declared implicitly due to the declaration of "=" (see 6.6);
7 any other implicitly declared subprogram unless it is a dispatching operation of a tagged type;
8 an inherited subprogram of a generic formal tagged type with unknown discriminants;
9 an attribute that is a subprogram;
10 a subprogram declared immediately within a protected_body.
11 The Access attribute is not allowed for Intrinsic subprograms.
12 The default calling convention is protected for a protected
subprogram, and for an access-to-subprogram type with the reserved word protected in its definition.
13 The default calling convention is entry for an entry.
- ----------------
1. What is the default convention of an entity not covered by 6.3.1, such as a record type? (Ada.)
- ----------------
2. Does an inherited or overriding subprogram have (by default) the same convention as the parent subprogram? (Yes.)
6.3.1(3) implies that if the calling convention of a parent subprogram is not Ada, the default convention of an overriding subprogram is, nonetheless, Ada. However, 3.9.2(10) says:
If the dispatching operation overrides an inherited subprogram, it shall be subtype conformant with the inherited subprogram.
6.3.1(17) requires matching conventions for subtype conformance. Thus, the default calling convention for this overriding case is illegal; the programmer must give a pragma specifying the convention in this case. This seems unfriendly.
On the other hand, 3.4(18) says:
18 The profile of an inherited subprogram (including an inherited enumeration literal) is obtained from the profile of the corresponding (user-defined) primitive subprogram of the parent type, after systematic replacement of each subtype of its profile (see 6.1) that is of the parent type with a corresponding subtype of the derived type. ...
And 6.1(22) says:
Associated with a profile is a calling convention.
These paragraphs seem to imply that an inherited subprogram inherits the calling convention of its parent, as part of the inherited profile.
- ----------------
3. Is an implicitly declared dispatching "/=" operator legal? (Yes.)
Paragraph 3.9.1(1) says that the primitive subprograms of a tagged type are called dispatching operations. Paragraph 3.9.2(10) goes on to say that a dispatching operation shall not be of convention Intrinsic. However, paragraph 6.3.1(6) says that "/=" declared implicitly due to the declaration of "=" is of convention Intrinsic, by default.
Together these imply that the "/=" implicitly declared due to the declaration of "=" of a tagged type is an illegal dispatching operation. Is this the intent? (No.)
!recommendation
(See summary.)
!wording
Add two bullets after 6.3.1(13): "If not listed above, the calling convention for any inherited or overriding dispatching operation of a tagged type is that of the corresponding subprogram of the parent type. The default calling convention for a new dispatching operation of a tagged type is the convention of the full view of the type.
The default convention of any entity not listed above is Ada."
Add a Note to 6.3.1.: "An implementation need not support a pragma Convention on a new dispatching operation that specifies a convention different from the convention of the type or its other dispatching operations."
The last two sentences of 3.9.2(10) should be replaced by: "The convention of an inherited or overriding dispatching operation is the convention of the inherited operation. An explicitly declared dispatching operation shall not have convention Intrinsic."
!discussion
1. The default convention ought to be Ada for any entity not covered by 6.3.1. The dispatching operations of a type ought to inherit the convention of the type, for convenient interfacing to other OOP languages. (See below for more discussion of this point.)
- ----------------
2. It is important that Ada allow clean interfaces to other programming languages. In particular, it is important that Ada's tagged types can be used to interface to other OOP languages.
If an Ada 95 implementation is tightly integrated with another language, such as C++ or Java, it is nice if an Ada tagged type can be declared as an extension of a (foreign) type (or class) of the other language. Presumably, all of the dispatching operations of this foreign type would be defined as imported, with the convention of that other language. When defining the type extension in Ada, it would be very inconvenient if every overriding would have to have a pragma Convention on it to match that of the inherited operation, as required by 3.9.2(10).
Hence, it seems appropriate to define the default calling convention of an overriding of an inherited dispatching operation to be the same as that of the corresponding operation on the parent type, rather than always being convention "Ada" as specified in 6.3.1(3).
For example:
package Java.Graphics is type Graphics_Obj is tagged limited private; procedure drawString(G : in out Graphics_Obj; S : String); pragma Import(Java, drawString); ... end Java.Graphics;
with Java.Graphics; use Java.Graphics; package Flight_Simulator is type Simulator_Obj is new Graphics_Obj with private; procedure drawString(S : in out Simulator_Obj; S : String); -- implicit: pragma Convention(Java, drawString); ... end Flight_Simulator;
The "pragma Convention(Java, ...);" should be implicit when overriding a dispatching operation with convention Java. Anything else would be illegal by 3.9.2(10), and it seems silly to require the programmer to litter their program with redundant "pragma Convention"s.
The Note B.1(42) - derived from 13.1 - implies permission of implementation-defined restrictions of interfacing pragmas. Hence an implementation will be allowed to reject the attempt to create "heterogeneous" tagged types, i.e., types having primitive operations of different, explicitly specified conventions or of explicity specified conventions different from the convention of the type.
- ---------------- 2.a. The "Breach of Privacy" Issue
Presently, the convention of a primitive subprogram can be specified in the private part of the declaring package. The current rules require explicit confirmation of this convention for overriding subprograms and thus constitute a breach of the privacy of the private part, since the user needs to know about this privately specified convention in order to make the overriding declaration legal.
We are very reluctant to mandate Convention pragmas in the visible part of the package. Although such a rule might be derivable from freezing rules, it nevertheless could create a compatibility problem for existing code.
The proposed new rule of inheriting the convention eases, but does not eliminate, the breach of privacy, as any explicitly specified convention will still need to confirm the inherited convention.
At the implementation level, both the existing and the proposed model breach the private part, as subtype conformance of overriding with inherited subprograms includes checking for equality of the convention.
- ---------------- 2.b. Deriving the convention of operations from the type
Having dispatching operations with the convention of some other OOP language, while the type is not represented according to the convention of this other language, will be almost impossible to implement. The "normal" case will be that both type and operations need the convention pragma. In this context, it makes little sense that the convention of primitive operations defaults to Ada rather than to the convention of their type. The user will be forced to repeat the pragma for all the operations of the type. Considerably more convenient is a model, in which the default convention of dispatching operations is inherited from the type, but overridable if the implementation allows for such mixed conventions.
Since current rules imply that the convention of a type needs to be specified for the full view of the type, such dependency creates yet another breach of privacy in the case of private tagged types. However, the breach already exists as explained in 2.a. and to then exploit it for more convenience to the user and a cleaner overall model seems justified.
Mandating the specification of the convention for the partial view in order to avoid the breach of privacy seems too much of an incompatibility for existing code.
- ----------------
3. Clearly, an implicitly declared dispatching "/=" should not automatically be illegal.
The proposed new wording precludes declaring a dispatching operation by renaming the Intrinsic "/=", which is good (since there is no real body associated with "/="). It does not make "/=" itself illegal, which is also good.
The reason for 6.3.1(4-10) making various subprograms Intrinsic is that these subprograms don't really exist in machine code. For example, an implementation would typically not generate any code for the implicitly-declared "/=" operator -- instead, it would call the "=" operator, and then do a "not" operation at the call site. We don't want to allow 'Access of such subprograms, because it would introduce an implementation burden -- the implementation would have to materialize these subprograms as real machine-code subprograms, which is not otherwise necessary.
A similar issue arises with 6.3.1, which says that an inherited subprogram of a generic formal type with unknown discriminants is of convention Intrinsic, by default.
The reason for this rule is obscure enough that it should have been documented in the AARM: Consider:
package P is type Root is tagged null record; procedure Proc(X: Root); end P;
generic type Formal(<>) is new Root with private; package G is ... end G;
package body G is ... X: Formal := ...; ... Proc(X); -- This is a dispatching call in Instance, because -- the actual type for Formal is class-wide. ... -- Proc'Access would be illegal here, because it is of -- convention Intrinsic, by 6.3.1(8). end G;
type Actual is new Root with ...; procedure Proc(X: Actual); package Instance is new G(Formal => Actual'Class); -- It is legal to pass in a class-wide actual, because Formal -- has unknown discriminants.
Within Instance, all calls to Proc will be dispatching calls, so Proc doesn't really exist in machine code, so we wish to avoid taking 'Access of it. 6.3.1(8) applies to those cases where the actual type might be class-wide, and makes these Intrinsic, thus forbidding 'Access.
The wording change to 3.9.2(10) shown above means that it's OK to have such an inherited subprogram. If the spec of G contained a type extension of Formal, then that type's inherited Proc would also have convention Intrinsic, which would be legal. However, an explicit overriding of that Proc would be illegal.
!appendix

!section 3.9.2(1)
!subject Implicit /= is a legal dispatching operation
!reference RM95 3.9.2(1,10)
!reference RM95 6.3.1(6)
!from Tucker Taft 95-07-06
!reference as: 95-5209.a Tucker Taft 95-7-6>>
!discussion

Paragraph 3.9.1(1) says that the primitive subprograms of a tagged
type are called dispatching operations.  Paragraph 3.9.2(10) goes
on to say that a dispatching operation shall not be of convention
Intrinsic.  However, paragraph 6.3.1(6) says that "/=" declared
implicitly due to the declaration of "=" is of convention Intrinsic.

Together these imply that the "/=" implicitly declarated due to the
declaration of "=" of a tagged type is an illegal dispatching operation.
Presumably 3.9.2(10) should be modified to say something like:

  An explicitly declared dispatching operation shall not have
  convention Intrinsic.

This precludes declaring a dispatching operation by renaming the
Intrinsic "/=", which is good (since there is no real body
associated with "/=").  It does not make "/=" itself illegal,
which is also good.

- -Tuck

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

!section 3.9.2(10)
!subject Convention of an overriding dispatching operation
!reference RM95-3.9.2(10)
!reference RM95-6.3.1(3)
!from Tucker Taft 95-11-21
!reference 95-5394.a Tucker Taft 95-11-21>>
!discussion

If an Ada 95 implementation is tightly integrated with another
language, such as C++ or Java, it is nice if an Ada tagged type
can be declared as an extension of a (foreign) type (or class) of the
other language.  Presumably, all of the dispatching operations of this
foreign type would be defined as imported, with the convention of
that other language.  When defining the type extension in Ada, it
would be very inconvenient if every overriding would have to have
a pragma Convention on it to match that of the inherited operation,
as required by 3.9.2(10).

Hence, it seems appropriate to define the default calling convention
of an overriding of an inherited dispatching operation to be the same as
that of the corresponding operation on the parent type, rather than
always being convention "Ada" as specified in 6.3.1(3).

For example:

    package Java.Graphics is
        type Graphics_Obj is tagged limited private;
        procedure drawString(G : in out Graphics_Obj; S : String);
        pragma Import(Java, drawString);
      ...
    end Java.Graphics;

    with Java.Graphics; use Java.Graphics;
    package Flight_Simulator is
        type Simulator_Obj is new Graphics_Obj with private;
        procedure drawString(S : in out Simulator_Obj; S : String);
        -- implicit: pragma Convention(Java, drawString);
     ...
    end Flight_Simulator;

The "pragma Convention(Java, ...);" should be implicit when overriding
a dispatching operation with convention Java.  Anything else would be
illegal by 3.9.2(10), and it seems silly to require the programmer
to litter their program with redundant "pragma Convention"s.

- -Tuck

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

!section 3.9.2(10)
!subject Convention of an overriding dispatching operation
!reference RM95-3.9.2(10)
!reference RM95-6.3.1(3)
!reference 95-5394.a Tucker Taft 95-11-21
!reference AI95-00117
!from Bob Duff
!reference 96-5759.a Robert A Duff 96-11-18>>
!discussion

Tucker wrote:

> Hence, it seems appropriate to define the default calling convention
> of an overriding of an inherited dispatching operation to be the same as
> that of the corresponding operation on the parent type, rather than
> always being convention "Ada" as specified in 6.3.1(3).

AI-117 responds to this issue.

At the Vermont ARG meeting, several folks suggested that the solution
should instead be that the dispatching operations should get their
default convention from the *type*.  That is, when interfacing to (say)
Java, one would normally want the type to be of Convention Java, and all
dispatching operations also Convention Java.  So a new dispatching
operation would get convention Java, and an overriding operation would
get the convention from the parent operation, which, unless explicitly
overridden, would be Java.  Presumably, a type extension should inherit
the parent type's convention.

I see a problem with this: For a private type, the Convention pragma
must appear in the private part.  If subprograms in the visible part
inherit their convention from the type, then we have a violation of
privacy.  That is, code in the private part would affect the legality of
'Access outside the package.

I also see a problem with Tucker's solution: Suppose package P declares
type T1, and package P.C declares T2 as a type extension of T1.  For a
primitive subprogram of T2, we don't necessarily know at the point of
declaration whether it overrides anything -- we might find out about
overriding in the private part of P.C.  If this operation inherits its
convention from the parent operation, then we have a violation of
privacy w.r.t. 'Access.  If it does not, then presumably it *must* have
a pragma Convention, which must match that of the parent op.

Actually, is it not worse?  Consider a simple example with no
inheritance.  A subprogram is declared in the visible part of a package,
and a pragma Convention is given in the private part.  How are clients
supposed to know whether 'Access is legal?

It seems odd that pragma Convention is allowed to be in the private part
for subprograms, and *required* to be in the private part, for private
types.

Another issue: 6.3.1 defines the default convention for subprograms, and
for access-to-subprogram types.  Should it not also define the default
convention for everything else (e.g. record types)?

Another issue: How are untagged derived types affected?  Note that an
overriding operation really has little to do with what it overrides,
except that it hides it.

- - Bob


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

!section 3.9.2(10)
!subject Convention of an overriding dispatching operation
!reference RM95-3.9.2(10)
!reference RM95-6.3.1(3)
!reference 95-5394.a Tucker Taft 95-11-21
!reference AI95-00117
!reference 96-5759.a Robert A Duff 96-11-18
!from Erhard Ploedereder
!reference 96-5775.a Erhard Ploedereder  96-11-28>>
!discussion

In 96-5759.a, Bob argues that the rules proposed in the AI and some
improvements suggested at the recent meeting all share the problem
that they violate the privacy principles of Ada.

This is true. However, the current ARM semantics do so in the very same way
by requiring the user to specify a pragma on inherited primitive operations,
while he has no business knowing about the Convention Pragma applied
privately to the original operation. In fact, the situation is worse than
under the AI: The RM requires explicit action to react to something
supposedly unknown. Under the AI, at least no such explicit action is
required, albeit that 'Access ramifications may exist (as they do for
the RM).

Bob argues further:
> Another issue: 6.3.1 defines the default convention for subprograms, and
> for access-to-subprogram types.  Should it not also define the default
> convention for everything else (e.g. record types)?

Very good point and it does need to be addressed. (Wouldn't this be a
natural fall-out of implicit inheritance of Convention from types, as I
understood the cited alternative solution suggested at the meeting ?)




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

Questions? Ask the ACAA Technical Agent