Version 1.7 of ais/ai-00401.txt

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

!standard 3.4(01)          05-10-27 AI95-00401/05
!standard 3.4(03)
!standard 3.4(05)
!standard 3.4(08)
!standard 3.4(17)
!standard 3.4(18)
!standard 3.4(22)
!standard 3.4(23)
!standard 3.4(23.1)
!standard 3.4(27)
!standard 3.4(35)
!standard 3.4.1(02)
!standard 7.3(16)
!standard 7.3(20)
!standard 9.1(9.1)
!standard 9.4(11)
!standard 12.5.1(05)
!standard 12.5.1(15)
!standard 12.5.1(21)
!standard 12.5.5(04)
!class amendment 05-01-25
!status Amendment 200Y 05-03-01
!status ARG Approved 7-0-3 05-02-13
!status work item 05-01-25
!status received 05-01-25
!priority High
!difficulty Medium
!subject Terminology for interfaces
!summary
(See proposal.)
!problem
The current wording calls "interface ancestor" an interface that is mentioned in an interface_list. This terminology is used in the description of derived types, interface types, private extensions, task and protected objects and types, and formal derived types.
It causes some confusion because the term "ancestor" is already a technical term in Ada 95, with a subtly different meaning. For example, a type is an ancestor of itself, but the "interface ancestor" relationship doesn't have that same property. In some cases where the word "ancestor" is used alone, it is unclear whether it is a shorthand for "interface ancestor" or a bona fide usage of the technical term. Also, the description of private extensions and formal private types makes use of the phrase "ancestor subtype" in context where interfaces also play a role, creating even more obscurity.
This terminology issue was briefly discussed in the context of AI 251, but at the time no good alternative was proposed, and it's only when reading the integrated manual that the ambiguities become obvious.
!proposal
We propose to call "progenitor" an interface mentioned in an interface_list. We then define "ancestor" to mean "parent or progenitor, any level". Most of the rules that use the words "parent" or "ancestor" remain valid with this definition, although in a few cases we need to say "parent or progenitor".
While the wording changes are numerous, they are mostly limited to 3.4 and 12.5.1. Note that not all changes are terminology changes; some are just plugging holes. For instance, there are a number of places where the wording say "parent" for rules that should also apply to interfaces. In other cases the new terminology fixes wording that was otherwise wrong or incomprehensible, depending on how the word "ancestor" was interpreted.
!wording
Change 3.4(1) to read:
A derived_type_definition defines a new type (and its first subtype) whose characteristics are derived from those of a parent type{, and possibly from progenitor types}.
Change 3.4(3) to read:
An interface_subtype_mark in an interface_list names a *progenitor subtype*; its type is the *progenitor type*. The parent_subtype_indication defines the parent subtype; its type is the parent type. A derived type has one parent type and zero or more {progenitor} types.
Change 3.4(5) to read:
If there is a record_extension_part, the derived type is called a record extension of the parent type. A record_extension_part shall be provided if and only if the parent type is a tagged type. An interface_list shall be provided only if the parent type is a tagged type.
Change 3.4(8) to read:
Each class of types that includes the parent type {or a progenitor type} also includes the derived type.
Change 3.4(17) to read:
For each user-defined primitive subprogram (other than a user-defined equality operator -- see below) of the parent type {or of a progenitor type} that already exists at the place of the derived_type_definition, there exists a corresponding inherited primitive subprogram of the derived type with the same defining name. Primitive user-defined equality operators of the parent type {and any progenitor types} are also inherited by the derived type, except when the derived type is a nonlimited record extension, and the inherited operator would have a profile that is type conformant with the profile of the corresponding predefined equality operator; in this case, the user-defined equality operator is not inherited, but is rather incorporated into the implementation of the predefined equality operator of the record extension (see 4.5.2).
Change 3.4(18) to read:
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 {or progenitor} type, after systematic replacement of each subtype of its profile (see 6.1) that is of the parent {or progenitor} type with a corresponding subtype of the derived type. For a given subtype of the parent {or progenitor} type, the corresponding subtype of the derived type is defined as follows:
Change 3.4(22) to read:
The same formal parameters have default_expressions in the profile of the inherited subprogram. Any type mismatch due to the systematic replacement of the parent {or progenitor} type by the derived type is handled as part of the normal type conversion associated with parameter passing -- see 6.4.1.
Change 3.4(23) to read:
If a primitive subprogram of the parent {or progenitor} type is visible at the place of the derived_type_definition, then the corresponding inherited subprogram is implicitly declared immediately after the derived_type_definition. Otherwise, the inherited subprogram is implicitly declared later or not at all, as explained in 7.3.1.
Delete the paragraph added after 3.4(23) by AI95-00251.
Change 3.4(27) to read (this includes the changes of AI-391):
For the execution of a call on an inherited subprogram, a call on the corresponding primitive subprogram of the parent {or progenitor} type is performed; the normal conversion of each actual parameter to the subtype of the corresponding formal parameter (see 6.4.1) performs any necessary type conversion as well. If the result type of the inherited subprogram is the derived type, the result of calling the {subprogram of the parent or progenitor} is converted to the derived type, or in the case of a null extension, extended to the derived type using the equivalent of an extension_aggregate with the original result as the ancestor_part and null record as the record_component_association_list.
Change the paragraph added after 3.4(35) by AI95-00251 to read:
An interface type {that} has a {progenitor type} "is derived from" that type. A derived_type_definition, however, never defines an interface type.
Change the second sentence of 3.4.1(2) as modified by AI95-00251 to read:
A derived type, interface type, type extension, task type, protected type, or formal derived type is also derived from every ancestor of each of its progenitor types, if any.
Change 7.3(16) to read:
A private extension inherits components (including discriminants unless there is a new discriminant_part specified) and user-defined primitive subprograms from its ancestor type {and its progenitor types (if any)}, in the same way that a record extension inherits components and user-defined primitive subprograms from its parent type {and its progenitor types} (see 3.4).
Add after 7.3(20):
The progenitor types specified in a private_extension_declaration and the progenitor types specified in the corresponding declaration of a record extension given in the private part need not be the same -- the only requirement is that the private extension must be descended from each interface from which the record extension is descended.
Delete the first paragraph added after 9.1(9.1) by AI95-00345.
Delete the sentence added to 9.4(11) by AI95-00345. (That, is revert to the original wording of RM95.)
Change 12.5.1(5) to read:
The ancestor subtype of a formal derived type is the subtype denoted by the subtype_mark of the formal_derived_type_definition. For a formal derived type declaration, the reserved words with private shall appear if and only if the ancestor type is a tagged type; in this case the formal derived type is a private extension of the ancestor type and the ancestor shall not be a class- wide type. Similarly, {an interface_list or} the optional reserved word abstract shall appear only if the ancestor type is a tagged type.
Change the paragraph added after 12.5.1(5) by AI95-00251 to read:
The actual type for a generic formal derived type shall be a descendant of every {progenitor} of the formal type.
Change 12.5.1(21) to read:
For a formal derived type, the predefined operators and inherited user-defined subprograms are determined by the ancestor type {and any progenitor types}, and are implicitly declared at the earliest place, if any, immediately within the declarative region in which the formal type is declared , where the corresponding primitive subprogram of the ancestor {or progenitor} is visible (see 7.3.1). In an instance, the copy of such an implicit declaration declares a view of the corresponding primitive subprogram of the ancestor {or progenitor} of the formal derived type, even if this primitive has been overridden for the actual type. When the ancestor {or progenitor} of the formal derived type is itself a formal type, the copy of the implicit declaration declares a view of the corresponding copied operation of the ancestor {or progenitor}. In the case of a formal private extension, however, the tag of the formal type is that of the actual type, so if the tag in a call is statically determined to be that of the formal type, the body executed will be that corresponding to the actual type.
Change 12.5.5(4) (a section introduced by AI95-00251) to read:
The actual type shall be a descendant of every {progenitor} of the formal type.
!discussion
(See proposal.)
!example
!corrigendum 3.4(01)
Replace the paragraph:
A derived_type_definition defines a new type (and its first subtype) whose characteristics are derived from those of a parent type.
by:
A derived_type_definition defines a new type (and its first subtype) whose characteristics are derived from those of a parent type, and possibly from progenitor types.
!corrigendum 3.4(03)
Replace the paragraph:
The parent_subtype_indication defines the parent subtype; its type is the parent type.
by:
The parent_subtype_indication defines the parent subtype; its type is the parent type. The interface_list defines the progenitor types (see 3.9.4). A derived type has one parent type and zero or more progenitor types.
!corrigendum 3.4(05)
Replace the paragraph:
If there is a record_extension_part, the derived type is called a record extension of the parent type. A record_extension_part shall be provided if and only if the parent type is a tagged type.
by:
If there is a record_extension_part, the derived type is called a record extension of the parent type. A record_extension_part shall be provided if and only if the parent type is a tagged type. An interface_list shall be provided only if the parent type is a tagged type.
!corrigendum 3.4(08)
Replace the paragraph:
by:
!corrigendum 3.4(17)
Replace the paragraph:
by:
!corrigendum 3.4(18)
Replace the paragraph:
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. For a given subtype of the parent type, the corresponding subtype of the derived type is defined as follows:
by:
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 or progenitor type, after systematic replacement of each subtype of its profile (see 6.1) that is of the parent or progenitor type with a corresponding subtype of the derived type. For a given subtype of the parent or progenitor type, the corresponding subtype of the derived type is defined as follows:
!corrigendum 3.4(22)
Replace the paragraph:
The same formal parameters have default_expressions in the profile of the inherited subprogram. Any type mismatch due to the systematic replacement of the parent type by the derived type is handled as part of the normal type conversion associated with parameter passing — see 6.4.1.
by:
The same formal parameters have default_expressions in the profile of the inherited subprogram. Any type mismatch due to the systematic replacement of the parent or progenitor type by the derived type is handled as part of the normal type conversion associated with parameter passing — see 6.4.1.
!corrigendum 3.4(23)
Replace the paragraph:
If a primitive subprogram of the parent type is visible at the place of the derived_type_definition, then the corresponding inherited subprogram is implicitly declared immediately after the derived_type_definition. Otherwise, the inherited subprogram is implicitly declared later or not at all, as explained in 7.3.1.
by:
If a primitive subprogram of the parent or progenitor type is visible at the place of the derived_type_definition, then the corresponding inherited subprogram is implicitly declared immediately after the derived_type_definition. Otherwise, the inherited subprogram is implicitly declared later or not at all, as explained in 7.3.1.
!comment the paragraph added by AI-251 is deleted.
!corrigendum 3.4(27)
Replace the paragraph:
For the execution of a call on an inherited subprogram, a call on the corresponding primitive subprogram of the parent type is performed; the normal conversion of each actual parameter to the subtype of the corresponding formal parameter (see 6.4.1) performs any necessary type conversion as well. If the result type of the inherited subprogram is the derived type, the result of calling the parent's subprogram is converted to the derived type.
by:
For the execution of a call on an inherited subprogram, a call on the corresponding primitive subprogram of the parent or progenitor type is performed; the normal conversion of each actual parameter to the subtype of the corresponding formal parameter (see 6.4.1) performs any necessary type conversion as well. If the result type of the inherited subprogram is the derived type, the result of calling the subprogram of the parent or progenitor is converted to the derived type, or in the case of a null extension, extended to the derived type using the equivalent of an extension_aggregate with the original result as the ancestor_part and null record as the record_component_association_list.
!corrigendum 3.4(35)
Insert after the paragraph:
17 If the reserved word abstract is given in the declaration of a type, the type is abstract (see 3.9.3).
the new paragraph:
18 An interface type that has a progenitor type "is derived from" that type. A derived_type_definition, however, never defines an interface type.
!corrigendum 3.4.1(02)
Replace the paragraph:
A derived type is derived from its parent type directly; it is derived indirectly from any type from which its parent type is derived. The derivation class of types for a type T (also called the class rooted at T) is the set consisting of T (the root type of the class) and all types derived from T (directly or indirectly) plus any associated universal or class-wide types (defined below).
by:
A derived type is derived from its parent type directly; it is derived indirectly from any type from which its parent type is derived. A derived type, interface type, type extension, task type, protected type, or formal derived type is also derived from every ancestor of each of its progenitor types, if any. The derivation class of types for a type T (also called the class rooted at T) is the set consisting of T (the root type of the class) and all types derived from T (directly or indirectly) plus any associated universal or class-wide types (defined below).
!corrigendum 7.3(16)
Replace the paragraph:
A private extension inherits components (including discriminants unless there is a new discriminant_part specified) and user-defined primitive subprograms from its ancestor type, in the same way that a record extension inherits components and user-defined primitive subprograms from its parent type (see 3.4).
by:
A private extension inherits components (including discriminants unless there is a new discriminant_part specified) and user-defined primitive subprograms from its ancestor type and its progenitor types (if any), in the same way that a record extension inherits components and user-defined primitive subprograms from its parent type and its progenitor types (see 3.4).
!corrigendum 7.3(20)
Insert after the paragraph:
7 The ancestor type specified in a private_extension_declaration and the parent type specified in the corresponding declaration of a record extension given in the private part need not be the same — the parent type of the full view can be any descendant of the ancestor type. In this case, for a primitive subprogram that is inherited from the ancestor type and not overridden, the formal parameter names and default expressions (if any) come from the corresponding primitive subprogram of the specified ancestor type, while the body comes from the corresponding primitive subprogram of the parent type of the full view. See 3.9.2.
the new paragraph:
8 The progenitor types specified in a private_extension_declaration and the progenitor types specified in the corresponding declaration of a record extension given in the private part need not be the same — the only requirement is that the private extension must be descended from each interface from which the record extension is descended.
!corrigendum 9.1(9.1/1)
Insert after the paragraph:
For a task declaration without a task_definition, a task_definition without task_items is assumed.
the new paragraphs:
For a task_type_declaration, if the first parameter of a primitive inherited subprogram is of the task type or an access parameter designating the task type, and there is an entry_declaration for a single entry with the same identifier within the task_type_declaration, having a profile that is type conformant with that of the inherited subprogram after omitting this first parameter, the inherited subprogram is said to be implemented by the conforming task entry.
Legality Rules
A task declaration requires a completion, which shall be a task_body, and every task_body shall be the completion of some task declaration.
Each interface_subtype_mark of an interface_list appearing within a task_type_declaration shall denote a limited interface type that is not a protected interface.
For each primitive subprogram inherited by the type declared by a task_type_declaration, at most one of the following shall apply:
If neither applies, the inherited subprogram shall be a null procedure.
!corrigendum 9.4(11)
Insert after the paragraph:
A protected_definition defines a protected type and its first subtype. The list of protected_operation_declarations of a protected_definition, together with the known_discriminant_part, if any, is called the visible part of the protected unit. The optional list of protected_element_declarations after the reserved word private is called the private part of the protected unit.
the new paragraphs:
For a protected_type_declaration, the first parameter of a primitive inherited subprogram is of the protected type or an access parameter designating the protected type, and there is a protected_operation_declaration for a protected subprogram or single entry with the same identifier within the protected_type_declaration, having a profile that is type conformant with that of the inherited subprogram after omitting this first parameter, the inherited subprogram is said to be implemented by the conforming protected subprogram or entry.
Legality Rules
A protected declaration requires a completion, which shall be a protected_body, and every protected_body shall be the completion of some protected declaration.
Each interface_subtype_mark of an interface_list appearing within a protected_type_declaration shall denote a limited interface type that is not a task interface.
For each primitive subprogram inherited by the type declared by a protected_type_declaration, at most one of the following shall apply:
If neither applies, the inherited subprogram is a null procedure.
If an inherited subprogram is implemented by a protected procedure or an entry, then the first parameter of the inherited subprogram shall be of mode out or in out, or an access-to-variable parameter.
!corrigendum 12.5.1(05)
Replace the paragraph:
The ancestor subtype of a formal derived type is the subtype denoted by the subtype_mark of the formal_derived_type_definition. For a formal derived type declaration, the reserved words with private shall appear if and only if the ancestor type is a tagged type; in this case the formal derived type is a private extension of the ancestor type and the ancestor shall not be a class-wide type. Similarly, the optional reserved word abstract shall appear only if the ancestor type is a tagged type.
by:
The ancestor subtype of a formal derived type is the subtype denoted by the subtype_mark of the formal_derived_type_definition. For a formal derived type declaration, the reserved words with private shall appear if and only if the ancestor type is a tagged type; in this case the formal derived type is a private extension of the ancestor type and the ancestor shall not be a class-wide type. Similarly, an interface_list or the optional reserved word abstract shall appear only if the ancestor type is a tagged type.
The actual type for a generic formal derived type shall be a descendant of every progenitor of the formal type.
!corrigendum 12.5.1(21)
Replace the paragraph:
For a formal derived type, the predefined operators and inherited user-defined subprograms are determined by the ancestor type, and are implicitly declared at the earliest place, if any, within the immediate scope of the formal type, where the corresponding primitive subprogram of the ancestor is visible (see 7.3.1). In an instance, the copy of such an implicit declaration declares a view of the corresponding primitive subprogram of the ancestor of the formal derived type, even if this primitive has been overridden for the actual type. When the ancestor of the formal derived type is itself a formal type, the copy of the implicit declaration declares a view of the corresponding copied operation of the ancestor. In the case of a formal private extension, however, the tag of the formal type is that of the actual type, so if the tag in a call is statically determined to be that of the formal type, the body executed will be that corresponding to the actual type.
by:
For a formal derived type, the predefined operators and inherited user-defined subprograms are determined by the ancestor type and any progenitor types, and are implicitly declared at the earliest place, if any, immediately within the declarative region in which the formal type is declared, where the corresponding primitive subprogram of the ancestor or progenitor is visible (see 7.3.1). In an instance, the copy of such an implicit declaration declares a view of the corresponding primitive subprogram of the ancestor or progenitor of the formal derived type, even if this primitive has been overridden for the actual type. When the ancestor or progenitor of the formal derived type is itself a formal type, the copy of the implicit declaration declares a view of the corresponding copied operation of the ancestor or progenitor. In the case of a formal private extension, however, the tag of the formal type is that of the actual type, so if the tag in a call is statically determined to be that of the formal type, the body executed will be that corresponding to the actual type.
!corrigendum 12.5.5(01)
!comment Just a dummy to trigger a conflict; the wording change is only in
!commentt paragraph 4.
@drepl The actual type shall be a descendant of every ancestor of the formal type. @dby The actual type shall be a descendant of every progenitor of the formal type.
!example
(See AI-251 and AI-345 for examples.)
!ACATS test
This is just terminology and minor glitches; any ACATS tests should be covered by those for the original AIs.
!appendix

From: Erhard Ploedereder
Sent: Tuesday, May 3, 2005  12:05 PM


The connection between "implemented_by" and "overridden by parent" that I
am/was worried about......

below is a description of what I was worried about -- however, meanwhile I
discovered that one sentence may save the day, i.e., makes my worrisome
examples illegal. The sentence is 3.4 (5/2, 2.sentence) in the version as I
have corrected the sentence. If the original version stays, you definitely
need to read on. The (corrected) sentence expresses the rule: have an
interface_list in a derived type definition, then the parent must be tagged
(which a task type is not).  The original rule poses the rule only if it is
a record extension part as well, making my examples legal (and troublesome).

The situation that I worried about starts out by the following:

task type T is
   entry do_this;
end T;

interface I;
   procedure do_this(X: I);

type NT is new T and I;

vs.

task type NNT is new I with
   entry do_this;
end NNT;

Compare NNT and NT. For NNT, clearly the entry implements I.do_this.
For NT, does it, too? It looks like "no, it doesn't" since the entry
of NT isn't declared top-level and hence no homograph to the inherited
I.do_this.

Lawyerly logical, "userly" a surprise when it works for NNT, but not for NT.

If this isn't fixed (or isn't so in the first place) then the one that
really worries me lawyerly and userly is

type N3T is new NT and NI;      - NI a descendant of I

For N3T, although the entry NT.do_it implements I.do_it, this won't be
recognized and there will be an obligation to override NI.do_it, although it
is I.do_it.

---
by a rather narrow margin, the following problem is avoided because prefixed
views require a tagged type object, which tasks aren't, and hence prefix
call notation is not available for the call to a subprog inherited from an
interface.

X: N3T;
...
X.do_it;

could be either a call on the entry or a prefix-notation call to the
inherited (and overridden) NI.do_it. (Of course, with a "unified view"
it wouldn't be a problem, since it's all one and the same.)

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

From: Randy Brukardt
Sent: Tuesday, May 3, 2005  1:38 PM

I think your version is what was intended; there is no intention to allow
derivation from a task type that has interfaces, or to allow derivation to
add interfaces without extension.

So we can ignore the rest of your explanation. Thank goodness. :-)

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

From: Erhard Ploedereder
Sent: Monday, May 2, 2005  8:38 PM

At the Paris meeting, I took an action item to check for overall consistency
of parent vs. ancestor vs. progenitor, etc etc, i.e., the whole terminology
that surrounds inheritance. Here is the outcome in sequence of the manual
D-11, not necessarily importance, although the first ones are pretty
significant; Pascal may rule one or the other out of bounds.

Erhard

-------------------------

Comments on Interface Semantics:
-------------------------------

I was unable to find a rule that allowed abstract subprograms inherited from
interfaces to be implemented by subprograms inherited from the parent. Such
a rule is essential and certainly is not derivable -quite the contrary- from
current abstract subprogram rules. Presently, it seems that all the
subprograms inherited from interfaces need to be explicitly implemented in a
concrete descendant type (since they are treated as inherited abstract
subprograms which must be overridden). THIS CANNOT POSSIBLY BE THE
INTENT OF INTERFACES.

Note in particular the interesting situation where a concrete parent type
implements Interface I and the derived type implements NI, a descendant of
I.  Here it is unavoidable that an implementation from a parent meets a spec
from a progenitor. This must be legal and there mustn't be a need to
override again what is already implemented for the parent.

The very thought that the accumulated load of subprogs of a specialized
interface needs to be explicitly wrapered again, merely because I wanted to
add the 3 very special routines there to my class hierarchy, is daunting.

-----------------

I did not find a rule that explained what happens when "almost
identical" subprogs are inherited from multiple interfaces, i.e., is
it o.k. to multiply inherit the same or mode- or subtype- or
type-conformant signatures?  (While this question was a bit
pathological in the context of homographs created by generic
instantiations where I believe calls become ambiguous, here it will be
commonplace and there better be an answer that allows them without any
problems, signature of the overriding winning in case of differences)

-----------------

I did not find a rule that allowed multiple subtype-conformant specs
inherited from multiple progenitors to be implemented by a single
overriding declaration. (Maybe none is needed; the words for the
"implemented-by" synchronized interfaces seem to work for multiple specs.
The words for abstract subprograms are not so resistant to doubt. )

--------------------

3.9.2 (20) dispatches only to overriding bodies, not to "implemented
by" bodies.  So dispatching doesn't work for implemented-by ops of
synchronized interfaces.  Fix 3.9.2(20) to include both kinds.

... or ...

Ceterum Censeo and hence you can ignore: to use the
overriding_indicator "overriding" for "implemented-by" bodies and, at
the same time, make a semantic rule that "implemented-by" is not
"overriding", is atrocious language design.  PLEASE; PLEASE, UNDO
THIS STUPID DISTINCTION BETWEEN OVERRIDING AND IMPLEMENTED-BY. It'll
bite again and again. Make it a principle that one dispatches (only) to
overriding subprogs (if and only if!)

---------------------------

3.4 (1.a); N (13):  Glossary...is a bit wrong now.

3.4 Rule is missing that interface lists allow only interface types !!!!
  (was found in 3.9.*; will be solved per decision at Paris mtg)

3.4 (5) should say "record_extension_part or an interface_list"  (and-> or;
  no parenthesis; Reason: simple logic)

3.4(15/2) "appears" (where?) -> "is present in the derived_type_definition."

-----
3.4 (16) are there no predefined ops for interface types ?
    '(17/2) for equality, the rules are wrong!!!
        consider: parent is limited interface; some progenitor has a
              user-defined "=" (but is limited);
              does the resulting type inherit "=" ?
              The rules say "no", they should say "yes", because the
              progenitor has equality (and the type better not be
              without the "="!!!)
              Does it matter beyond the limited type case? Probably not,
              because the new type has its own predefined equality, which
              now implements the "="; unless...
    (17/2) if there are other predefined primitive ops for interfaces, they
           need to be dealt with here. Are there?
-----

3.4 (21) what if the parent type is an interface type, as is allowed ?
Then the sentence makes no sense, since the parent (sub)type should be
seen as infinite, should it not?
If the sentence should apply to interface parents, the principle should
apply to the interfaces inherited from progenitors as well in the context of
the co-variant inheritance. Admittedly, it seems to be trivially true today,
since interfaces don't have discriminants; but I am bothered by "shortening"
the rule just because this is how it is in today's definition.  The
"convertability" ought to be to all ancestors.

------

3.9 terminology: interface vs interface type ... note that normally the
  prefix term is reserved for the objects of the type. E.g., the task X of
  task type T.
  Here "interface" is sometimes used to mean interface type.
  1.b.2/2; 12.a/2, 3.9.1 4.m/2, ....
  Should be fixed.
The fact that the abbreviation is in fact defined (in 3.9.4 (3/2)), makes it
legit, but still not helpful, just lazy.
  X: I;  -- the interface X of interface I ??????

-------

3.9.(1k) 2.line "parent" -> "parent or progenitor"; the rule applies
to the inherited subprograms originating from normal progenitors as
well.
Anything to be stated about synchronized progenitors?

----------

3.9. 2/2   typo: ...interface type is [a] tagged type.

--------

3.9.1 3/2 2.sentence : parent -> the parent or a progenitor type !!
          (the sentence definitely applies to both)
          (Remember: it is possible that the parent type is an interface,
           so it is legit to have a limited parent, but a non-limited type
           here.)

---------

3.9.2(10/1) <<<most comments obsolete due to discussion at Paris
meeting and lawyerly distinction made between implemented by and
overriding for synchronized types. note: if the distinction goes away,
convention rules are needed here.>>>

However there is one case remaining: inheriting a null procedure from
a progenitor or redefining it: what is the Convention? So far,
3.9.2(10/1) only talks about inheriting from parent types.

---------

3.9.3 (4/2) I could not parse the sentence in less than 3 minutes (and
still am unsure of what it tries to say); an earlier comment said that
I could not parse it at all. 3 minutes helped. Still unsure what the
"or a type other than..." binds to (the type, the parent or the
ancestor type or none of the above).  Now I need 30 minutes of
semantic analysis. :-)

---------

The argument in 4.5.2 (14.b/2) seems wrong: formal derived types can also
have parent types. Are they full types?

--------

4.6 23.b  "parent -> ancestor" !
          because conversions also from progenitors (in fact ancestors in
          general)

---------

7.3.(20) : "definitely to be extended to the progenitors !" is my original
          note. 20.1/2 does that. What remains is some worry that the words
          in 20 may be wrong in case the parent is an interface type.

---------

7.5 (2/2) : no brackets please (where is it derivable from?)

---------
7.6 Could Controlled become interface now ????
    I know that this is "far out", but it would do away with the bloody
    nuisance that Controlledness cannot be mixed-in today. (It would
    require "magic" by the compiler, since it presumably involves data.
    Just a thought and yes, shoot the engineer.)
----------

9.1  (9.2/2) typo: profile of [the] inherited subprog

------

9.1  (9.d/2)
   what is a name interface? how does the first part of the sentence parse?
   missing "a" in "Only [a] limited"

   same comments for 9.4 11.d/2


-------
12.5.1 (5.1/2) actual must descend all progenitors, but NOT the parent ???
               (while later rules deal with the parent, it is really bad
                description to not include the parent here)

------

12.5.1. (21/2) typo "progentor";  typo missing blank in "ancestoror"
        The content is bogus; apparently the "and progenitor" in the
        first sentence was added in the wrong place. Should be added
        after "by the ancestor type" and should say "and any
        progenitor types"
        there is a displaced blank later "  or progenitoris"

12.5.1. (21.a/2) typo "progentor" and double blank before it
---------


A (musing) observation:

Interface Interf;
procedure foo(X: Interf) is null;
procedure bar(X: Interf);

seems that just about the only place in the code where I can mutter
"Interf" is in an interface_list. Everywhere else, it's Interf'Class to
be usable at all, since I cannot have objects of type Interf.
Correct?
If not so, enlighten me. But then, it'll come as a bloody surprise that
procedure test(X: Interf) is
begin
     bar(X); -- dispatching call, of course
     foo(X); -- does not dispatch; does nothing
end test;
I wanted a "null" at the bottom of a dispatching wrapper hierarchy, but this
defeats the very idea and makes the call non-dispatching.

----------------

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

From: Randy Brukardt
Sent: Monday, May 2, 2005  10:24 PM

> I did not find a rule that explained what happens when "almost
> identical" subprogs are inherited from multiple interfaces, i.e., is
> it o.k. to multiply inherit the same or mode- or subtype- or
> type-conformant signatures?  (While this question was a bit
> pathological in the context of homographs created by generic
> instantiations where I believe calls become ambiguous, here it will be
> commonplace and there better be an answer that allows them without any
> problems, signature of the overriding winning in case of differences)

That's the purpose of 8.3(12.1-12.3 and 26.1-26.2). I suggest reading these
rules carefully to see if they cover this and other questions that you raise
here, and (if your head doesn't explode first ;-), report your findings. (I
believe that they do, but I have to save my head for the AARM and all of the
other editorial comments.)

>
> -----------------
>
> I did not find a rule that allowed multiple subtype-conformant specs
> inherited from multiple progenitors to be implemented by a single
> overriding declaration. (Maybe none is needed; the words for the
> "implemented-by" synchronized interfaces seem to work for multiple specs.
> The words for abstract subprograms are not so resistant to doubt. )

See above. It seems that you missed 8.3 altogether.

> --------------------
>
> 3.9.2 (20) dispatches only to overriding bodies, not to "implemented
> by" bodies.  So dispatching doesn't work for implemented-by ops of
> synchronized interfaces.  Fix 3.9.2(20) to include both kinds.

This looks like a hole.

> ... or ...
>
> Ceterum Censeo and hence you can ignore: to use the
> overriding_indicator "overriding" for "implemented-by" bodies and, at
> the same time, make a semantic rule that "implemented-by" is not
> "overriding", is atrocious language design.  PLEASE; PLEASE, UNDO
> THIS STUPID DISTINCTION BETWEEN OVERRIDING AND IMPLEMENTED-BY. It'll
> bite again and again. Make it a principle that one dispatches (only) to
> overriding subprogs (if and only if!)

I can't ignore it, I don't know Latin. (A US public school education. :-)

I think this is a damned if you do, damned if you don't situation. The
differences between "overriding" and "implemented by" are significant enough
that we *have* to have some terminological difference between them. I suppose
we could stick some sort of adjective on "overriding", say "normal overriding"
and "prefixed overriding", and then try to make all of the rules work. But if
we do that, I hope Ada Europe has some more money to spend on this, because it
would take a lot of work to carefully check everything  several more times.

I'll leave someone else to look over the rest of it. (Or do it some other time;
say September.)

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

From: Tucker Taft
Sent: Monday, May 2, 2005  11:29 PM

> 3.9.2 (20) dispatches only to overriding bodies, not to "implemented
> by" bodies.  So dispatching doesn't work for implemented-by ops of
> synchronized interfaces.  Fix 3.9.2(20) to include both kinds.

Good point.  We should include bodies that are implemented by
protected operations or task entries as legitimate, albeit
compiler-generated, bodies.

>
> .. or ....
>
> Ceterum Censeo and hence you can ignore: to use the
> overriding_indicator "overriding" for "implemented-by" bodies and, at
> the same time, make a semantic rule that "implemented-by" is not
> "overriding", is atrocious language design.  PLEASE; PLEASE, UNDO
> THIS STUPID DISTINCTION BETWEEN OVERRIDING AND IMPLEMENTED-BY. It'll
> bite again and again. Make it a principle that one dispatches (only) to
> overriding subprogs (if and only if!)

I understand your concern, but as Randy points out, the distinction
is quite important.  The notion of a compiler-provided "wrapper" is
pretty fundamental for the semantics to make sense here.  For example,
the formal parameter names and the defaults come from the inherited
subprogram, not from the protected/task op, when you call this
operation in non-prefix notation.  That pretty much has to be true
since the protected/task op doesn't even have a formal parameter
name for the first parameter.

It is unfortunate that the overriding indicator mucks up the
terminology situation even further.  Perhaps Randy's idea of
calling it "prefixed overriding" could help, though I think
he is right that we could run into more confusion that way
(analogous to the old confusion that a "generic package" is
*not* a package).

On the issue of interface semantics in general,
as Randy pointed out, you seem to have missed
8.3 completely, and that is where all the tricky rules
are that relate to inheritance and overriding between
multiple interface ancestors.  It sounds like we should
have some sort of "pointer" to 8.3 from 3.9.4 (or 3.4), and/or
summarize the rules in 3.9.4 (or 3.4) in AARM redundancy brackets.

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

From: Erhard Ploedereder
Sent: Tuesday, May  3, 2005  6:28 AM

> I understand your concern, but as Randy points out, the distinction
> (of "overriding" and "implemented-by") is quite important.

No argument given. Of course it is important...however, distinction does not
necessarily imply exclusion. For example, call it "protected overriding" or
"synchronized overriding" (and all overriding rules apply, except for the
ones that "implemented by" presently modifies; the only other place to
also modify is the identified one on Convention).

Actually, give me an answer to comment Uno first, which does have a bearing
on the problem: are we serious that ops inherited from an interface cannot
be implemented by the parent?  If this is so, the interface capability is
about as useful as Ada95 OOP was a few months prior to its release, when it
didn't work at all for objects designated by access values.  If this is not
so, one needs to deal with interface ops implemented by inherited protected
ops anyway, which equally require "implemented-by" rules.

(I'll react to the 8.3 pointer separately.)

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

From: Tucker Taft
Sent: Tuesday, May  3, 2005  7:53 AM

> ...
> Actually, give me an answer to comment Uno first, which does have a bearing
> on the problem: are we serious that ops inherited from an interface cannot
> be implemented by the parent?

This sentence sounds like the famous "when did you stop
beating your wife?" question.  The answer is that a non-abstract
operation inherited from one ancestor can override
an abstract operation inherited from another.

This is based on 8.3(12.1/2...):

   If two or more homographs are implicitly declared at the same place:

     * If one is a non-null non-abstract subprogram, then it overrides
       all [which] {that} are null or abstract subprograms.

     * If all are null procedures or abstract subprograms, then any null
       procedure overrides all abstract subprograms; if more than one
       homograph remains that is not thus overridden, then one is chosen
       arbitrarily to override the others.

There are some legality rules in 8.3(26.1/2) which guarantee when
one is chosen arbitrarily, the choice doesn't matter, because they
all must conform fully in that case.  But the rule you care about
is the first one, namely a non-null, non-abstract inherited
subprogram overrides all the null or abstract ones.  That gives
you the effect you (and we all) want.


 > ...
  If this is so, the interface capability is
> about as useful as Ada95 OOP was a few months prior to its release, when it
> didn't work at all for objects designated by access values.  If this is not
> so, one needs to deal with interface ops implemented by inherited protected
> ops anyway, which equally require "implemented-by" rules.

I don't see the connection.  The "implemented-by" rules
for protected/task operations rely on a "wrapper" model,
somewhat analogous to the way renaming-as-body is
described.  The rules given in 8.3 are about one
inherited operation overriding another.

The wording in 3.9.2(20), which doesn't seem to work very
well for the "implemented-by" case, does seem to handle
adequately this case of one inherited operation overriding
another (surprisingly).

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

From: Pascal Leroy
Sent: Monday, May  9, 2005 10:29 AM

> 3.9.2 (20) dispatches only to overriding bodies, not to
> "implemented by" bodies.  So dispatching doesn't work for
> implemented-by ops of synchronized interfaces.  Fix 3.9.2(20)
> to include both kinds.

Yep, that's a bug.

> PLEASE; PLEASE, UNDO THIS STUPID DISTINCTION BETWEEN
> OVERRIDING AND IMPLEMENTED-BY. It'll bite again and again.
> Make it a principle that one dispatches (only) to overriding
> subprogs (if and only if!)

Let's not go there.  As others have indicated, the difference is very
significant from the language design standpoint.  Hopefully users should
be able to ignore it most of the time, which is why I think that
overriding_indicator is fine.

Maybe this could have been better described by a 2-step mechanism: (1) the
inherited operation is *overridden* by an implicit, subtype conformant
subprogram and (2) this implicit subprogram is *implemented by* calling
the entry or protected operation with the appropriate parameter mucking
(and possibly different defaults, convention, etc.).  This would have made
the wrapper model explicit, and dispatching would have worked "naturally".
However it is too late to revise the wording in this direction, and this
is insufficiently broken anyway.

> 3.4 (5) should say "record_extension_part or an
> interface_list"  (and-> or;
>   no parenthesis; Reason: simple logic)

In a subsequent message you wrote "have an interface_list in a derived
type definition, then the parent must be tagged (which a task type is
not)".  Hmm.  Unfortunately, a task type *may* be tagged, precisely if it
is derived from one or more interfaces (that's important for Class to
work, see 3.9(2.1)).  So we need to say that the parent is not a tagged
task or protected type.  It would be simple enough to say "if and only if
the parent type is a tagged record type".  But what about privacy?
Consider:

	package P is
	   type T is tagged limited private;
	private
	   task type T is new I with ...
	end P;

	type NT is new P.T with ...; -- Legal?  Hopefully not!

HELP!  What is it that makes NT illegal?

> 3.4 (16) are there no predefined ops for interface types ?
>     '(17/2) for equality, the rules are wrong!!!
>         consider: parent is limited interface; some progenitor has a
>               user-defined "=" (but is limited);
>               does the resulting type inherit "=" ?
>               The rules say "no", they should say "yes", because the
>               progenitor has equality (and the type better not be
>               without the "="!!!)

I think you have a point here.  One option would be to say that if some
progenitor has an "=" (user-defined or not) you cannot use it to declare a
limited type.  Another option would be to say that if you declare a
limited type you inherit any user-defined "=" as you would inherit any
other user-defined operation.  I think I'd prefer the 1st option, as it
would make the rules more uniform.

> 3.9.1 3/2 2.sentence : parent -> the parent or a progenitor type !!
>           (the sentence definitely applies to both)

Agreed.

> 3.9.3 (4/2) I could not parse the sentence in less than 3
> minutes (and still am unsure of what it tries to say);

Fair enough, but you cannot just groan, you have to propose a rewrite
(have fun).

> The argument in 4.5.2 (14.b/2) seems wrong: formal derived
> types can also have parent types. Are they full types?

Formal derived types don't have a parent, only a "ancestor subtype"
(12.5.1(5/2)).

> 7.6 Could Controlled become interface now ????

It would be nice, but there are nasty problems associated with that.  For
instance, you would have to assume that any object of a class-wide type
could be controlled, because Controlled could be mixed in at any level.
This wouldn't help code performance.

> 9.1  (9.d/2)
>    what is a name interface? how does the first part of the
> sentence parse?
>    missing "a" in "Only [a] limited"

Here "name" is a verb and "interfaces" a noun.  I think the sentence is
fine.

> 12.5.1. (21/2) typo "progentor";  typo missing blank in "ancestoror"
>         The content is bogus; apparently the "and progenitor" in the
>         first sentence was added in the wrong place.

Right.  The AI has the correct text.  Randy was tired.

> Interface Interf;
> procedure foo(X: Interf) is null;
> procedure bar(X: Interf);

(I won't comment on the weird syntax for declaring Interf ;-)  Bar must be
abstract, because null and abstract are your only choices for primitive
subprograms of interfaces.  Therefore...

> But then, it'll come as a bloody
> surprise that procedure test(X: Interf) is begin
>      bar(X); -- dispatching call, of course
>      foo(X); -- does not dispatch; does nothing
> end test;

... this is not even legal because the non-dispatching call to (the
presumably abstract) Bar is a no-no.  So no bloody surprise here.

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

From: Bob Duff
Sent: Monday, May  9, 2005  1:59 PM

> 	package P is
> 	   type T is tagged limited private;
> 	private
> 	   task type T is new I with ...
> 	end P;
>
> 	type NT is new P.T with ...; -- Legal?  Hopefully not!
>
> HELP!  What is it that makes NT illegal?

Isn't that illegal by 3.9.4(10/2) (in the 13 April 2005 version)?

> > 3.4 (16) are there no predefined ops for interface types ?
> >     '(17/2) for equality, the rules are wrong!!!
> >         consider: parent is limited interface; some progenitor has a
> >               user-defined "=" (but is limited);
> >               does the resulting type inherit "=" ?
> >               The rules say "no", they should say "yes", because the
> >               progenitor has equality (and the type better not be
> >               without the "="!!!)
>
> I think you have a point here.  One option would be to say that if some
> progenitor has an "=" (user-defined or not) you cannot use it to declare a
> limited type.  Another option would be to say that if you declare a
> limited type you inherit any user-defined "=" as you would inherit any
> other user-defined operation.  I think I'd prefer the 1st option, as it
> would make the rules more uniform.
>

I think I prefer the 2nd option.  Ada 95 allows user-defined "=" on
limited types, and it can be inherited.  Wouldn't the 1st option above
seem like an annoying arbitrary restriction?

> > 7.6 Could Controlled become interface now ????
>
> It would be nice, but there are nasty problems associated with that.  For
> instance, you would have to assume that any object of a class-wide type
> could be controlled, because Controlled could be mixed in at any level.
> This wouldn't help code performance.

Isn't that already the case, since you can add controlled components?
So even if the class-wide type is not itself controlled, it might need
finalization.  (Yes, I agree that's an annoying efficiency hit -- but I
think it already exists.)

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

From: Robert I. Eachus
Sent: Monday, May  9, 2005  2:21 PM

Pascal Leroy wrote:

>>3.4 (16) are there no predefined ops for interface types ?
>>    '(17/2) for equality, the rules are wrong!!!
>>        consider: parent is limited interface; some progenitor has a
>>              user-defined "=" (but is limited);
>>              does the resulting type inherit "=" ?
>>              The rules say "no", they should say "yes", because the
>>              progenitor has equality (and the type better not be
>>              without the "="!!!)
>>
>>
>
>I think you have a point here.  One option would be to say that if some
>progenitor has an "=" (user-defined or not) you cannot use it to declare a
>limited type.  Another option would be to say that if you declare a
>limited type you inherit any user-defined "=" as you would inherit any
>other user-defined operation.  I think I'd prefer the 1st option, as it
>would make the rules more uniform.

And I prefer the second option, as I think it provides a necessary
capability.  Where you need it, it would be frustrating and error prone
not to allow a user defined "=" to be inherited.  There are cases where
copying of a type makes no sense, but equality (actually identity) is
well defined and needed.  For example, I have some code that has to
check if two elements of a task type are the same task.  (Yes, it is
checking an error case where two parameters shouldn't be the same task
from an array, but it is much clearer to pass the task objects as
parameters rather than their indexes.  And of course due to the nature
of abstractions, you have nested calling, etc.  )  So in this case, the
*with* (or if you prefer the *use*) of Task_Identity is limited to the
definition of "=" not spread throughout the code.

Yes, I could overload some other operator, but we really shouldn't be
going there.

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

From: Tucker Taft
Sent: Monday, May  9, 2005  3:05 PM

...
> I think I prefer the 2nd option.  Ada 95 allows user-defined "=" on
> limited types, and it can be inherited.  Wouldn't the 1st option above
> seem like an annoying arbitrary restriction?

I agree with Bob.  There should not be anything special about "=" --
if you extend a limited interface that has "=" then you must
override it.  I'm a little unclear why we need to say anything.
Clearly if it has a predefined "=", then it is not a limited
interface, so we are only talking about user-defined "=".

>>>7.6 Could Controlled become interface now ????
>>
>>It would be nice, but there are nasty problems associated with that.  For
>>instance, you would have to assume that any object of a class-wide type
>>could be controlled, because Controlled could be mixed in at any level.
>>This wouldn't help code performance.
>
> Isn't that already the case, since you can add controlled components?
> So even if the class-wide type is not itself controlled, it might need
> finalization.  (Yes, I agree that's an annoying efficiency hit -- but I
> think it already exists.)

Efficiency isn't the only problem.  J.P. Rosen brought this up
several months ago, and alas, we had some pretty convincing
reasons why we couldn't do this.  The main reason is that
we don't allow "hidden" interfaces.  Right now, there are plenty
of types that hide the fact they are controlled (e.g. Unbounded_String
is likely to be implemented that way).  These would all become
illegal if we made Controlled into an interface.  I tried to rethink
whether we could allow "hidden" interfaces under certain circumstances,
such as when all the primitives of the interface are null procedures,
but that really didn't solve the problem.  The main issue is that
if a type has a hidden interface, and then you extend the type and
add an explicit derivation from that same interface, you are likely
going to screw things up with the implementation of the hidden
interface.  In particular, if someone implemented Controlled
in a hidden way and defined Finalize to do something, if you
then on some extension implement Controlled visibly, and override
Finalize to do something completely different, the "hidden" Finalize
operation is no longer going to be performed.

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

From: Gary Dismukes
Sent: Monday, May  9, 2005  3:30 PM

> > HELP!  What is it that makes NT illegal?
>
> Isn't that illegal by 3.9.4(10/2) (in the 13 April 2005 version)?

Right, that prevents it.

> > I think you have a point here.  One option would be to say that if some
> > progenitor has an "=" (user-defined or not) you cannot use it to decl are
> > a limited type.  Another option would be to say that if you declare a
> > limited type you inherit any user-defined "=" as you would inherit any
> > other user-defined operation.  I think I'd prefer the 1st option, as it
> > would make the rules more uniform.
>
> I think I prefer the 2nd option.  Ada 95 allows user-defined "=" on
> limited types, and it can be inherited.  Wouldn't the 1st option above
> seem like an annoying arbitrary restriction?

The second option seems better to me as well (more natural and flexible).

> > > 7.6 Could Controlled become interface now ????
> >
> > It would be nice, but there are nasty problems associated with that.  For
> > instance, you would have to assume that any object of a class-wide type
> > could be controlled, because Controlled could be mixed in at any level.
> > This wouldn't help code performance.
>
> Isn't that already the case, since you can add controlled components?
> So even if the class-wide type is not itself controlled, it might need
> finalization.  (Yes, I agree that's an annoying efficiency hit -- but I
> think it already exists.)

As Tuck points out (and as I was about to before I saw his message...),
that's a no-go (because of the 3.9.4(10/2) rule you cited:).  Oh well.
If it weren't for that restriction, I think you're right that the
implementation wouldn't add any significant difficulty beyond what
compilers already have to do for handling finalization on class-wide
objects.

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

From: Randy Brukardt
Sent: Monday, May  9, 2005  3:50 PM

> As Tuck points out (and as I was about to before I saw his message...),
> that's a no-go (because of the 3.9.4(10/2) rule you cited:).  Oh well.
> If it weren't for that restriction, I think you're right that the
> implementation wouldn't add any significant difficulty beyond what
> compilers already have to do for handling finalization on class-wide
> objects.

I disagree, there is a lot more complication. That's because type Controlled
may have (hidden) components to provide the control data necessary for
finalization. (I'd expect that to be a likely implementation, but I don't
know of other compilers do that.) Interfaces don't have data. Making
Controlled an interface would require the compiler to have some way to
handle having data for interfaces. It would be aggrevating to have to
implement that fully *and* not be able to use it for any other purpose.

In addition, as Tucker pointed out, interfaces are essentially a Boolean
proposition: either they are present or they are not present. That means
that there is no way to deal with hidden overriding routines (there can be
only one overriding), and certainly we don't want the incompatibility of
requiring all controlled types to be visible.

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

From: Gary Dismukes
Sent: Monday, May  9, 2005  6:41 PM

> I disagree, there is a lot more complication. That's because type Controlled
> may have (hidden) components to provide the control data necessary for
> finalization. (I'd expect that to be a likely implementation, but I don't
> know of other compilers do that.) Interfaces don't have data. Making
> Controlled an interface would require the compiler to have some way to
> handle having data for interfaces. It would be aggrevating to have to
> implement that fully *and* not be able to use it for any other purpose.

You're probably right that it has significant additional complications
because of internal components on the root types.  Anyway, I wasn't
trying to argue in favor of making those types interfaces, just that
I thought it wouldn't be that hard if we didn't have the restriction
(looks like I was probably wrong about that).

> In addition, as Tucker pointed out, interfaces are essentially a Boolean
> proposition: either they are present or they are not present. That means
> that there is no way to deal with hidden overriding routines (there can be
> only one overriding), and certainly we don't want the incompatibility of
> requiring all controlled types to be visible.

I wouldn't say there's no way of dealing with hidden overriding operations.
The AARM discusses the alternatives and explains that the restriction
is basically a methodological one.  The outside one could be defined to
override, but I agree that we don't want that.  In short, I agree with
the restriction requiring that inheritance from interfaces be visible.

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

From: Bob Duff
Sent: Monday, May  9, 2005  7:29 PM

> Efficiency isn't the only problem.

I wasn't arguing in favor of making Limited_[Controlled] an interface --
just commenting on the efficiency point.  If nothing else, it's too
late.

I'm still interested in the technical issue, though.  In particular, if
we weren't worried about compatibility, would the best solution be to
make these types interfaces, and thereby forbid hidden controlledness?

(I understand Randy's point about data in these types.)

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

From: Randy Brukardt
Sent: Monday, May  9, 2005  7:49 PM

I think so, actually. I could imagine handling the data through background
magic of some sort, and that wouldn't be so nasty if it had been designed in
from the beginning.

Similarly, if we weren't worried about compatibility at all, we'd probably
use some other mechanism for data hiding (this one is pretty messy for OO),
and hopefully eliminate problems with hidden inferfaces (so those would be
allowed). [One possibility would be automated composition of primitives.]

But of course that wouldn't resemble Ada that much (at least semantically),
so this is rather off-topic.

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

From: Tucker Taft
Sent: Monday, May  9, 2005  10:24 PM

The "best" possible solution probably makes Initialize
and Finalize into user-specifiable attributes, analogous
to Read and Write.  And they would probably automatically
compose, etc.

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

From: Robert I. Eachus
Sent: Monday, May  9, 2005  11:33 PM

Is that a proposal for Ada1Z?

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

From: Tucker Taft
Sent: Monday, May  9, 2005  11:50 PM

Actually, it was a proposal for Ada 9X which never made it.

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

From: Pascal Leroy
Sent: Tuesday, May 10, 2005  4:23 AM

> And I prefer the second option, as I think it provides a necessary
> capability.  Where you need it, it would be frustrating and error prone
> not to allow a user defined "=" to be inherited.  There are cases where
> copying of a type makes no sense, but equality (actually identity) is
> well defined and needed.

That makes sense.  Remember though that there is no code associated with
interfaces, so any user-defined "=" has to be abstract.  So this
capability is quite limited, although I can see that it would be useful at
times.

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

From: Robert I. Eachus
Sent: Tuesday, May 10, 2005  5:28 PM

I did a double-take when I read that, then realized (I hope) that Pascal
meant to say that subprograms in  interfaces are abstract and do not
have explicit bodies.  Or am I wrong?  I looked at AI-251, and it says:

All primitive subprograms must be abstract or null.

Seems pretty clear. But haven't we been assuming that there is a
(non-abstract) equality for non-limited interfaces?  It is probably
reasonable to assume that 'Read and 'Write for interface types are
abstract, but what about 'Class'Read and 'Class'Write?

I had just assumed that I could write:

package P is

   type I is interface;

   package Ops is
      function "="(Left, Right: I) return Boolean is
      begin return Left'Address = Right'Address; end "="
   end Ops;

end P;

It would be nice to be able to dispense with the package Ops, but now I
am begining to wonder if there are any predefined operations or
attributes for interface types.

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

From: Randy Brukardt
Sent: Tuesday, May 10, 2005  5:42 PM

> Seems pretty clear. But haven't we been assuming that there is a
> (non-abstract) equality for non-limited interfaces?

Predefined-equality is weird, but Tucker concluded it worked OK. And
interfaces make my head hurt. :-)

> It is probably
> reasonable to assume that 'Read and 'Write for interface types are
> abstract, but what about 'Class'Read and 'Class'Write?

The stream attributes have their own rules; they're always around, but in
some cases you can't call them. There was little consideration of
abstractness and stream attributes in the first place.

Anyway, go read the availability rules in 13.13.2(39-49/2) in the draft 11
AARM. You should be able to figure out any answer about stream attributes
there (although they might make *your* head hurt); if you can't, then tell
us what you think the hole is.

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

From: Robert I. Eachus
Sent: Tuesday, May 10, 2005  9:56 PM

>Predefined-equality is weird, but Tucker concluded it worked OK. And
>interfaces make my head hurt. :-)
>
I think the problem is that the reserved word appears in the wrong
place.  Technically interface *types *appear in interface* packages.
*How do you know that a package is an interface package?  Because it
contains interface types.  I would much prefer for the syntax to
require: *interface package* Foo *is*... *type* Bar *is interface*;...
*end* Foo;  Just syntactic sugar, but it would make it clear that this
is a funny kind of package because it contains interfaces.

>Anyway, go read the availability rules in 13.13.2(39-49/2) in the draft 11
>AARM. You should be able to figure out any answer about stream attributes
>there (although they might make *your* head hurt); if you can't, then tell
>us what you think the hole is.

I'll do that, and if I have trouble I'll tell you where the new hole in
my head is. ;-)

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

From: Pascal Leroy
Sent: Wednesday, May 11, 2005  3:53 AM

> Seems pretty clear. But haven't we been assuming that there is a
> (non-abstract) equality for non-limited interfaces?

There is certainly a non-abstract equality for non-limited interface, and
it returns True (much like for a null record) and it get incorporated into
the "=" for types whose parent is the interface.

> It is probably
> reasonable to assume that 'Read and 'Write for interface types are
> abstract, but what about 'Class'Read and 'Class'Write?

Don't assume anything!

For interfaces, just like for any good old abstract type, 'Read and 'Write
are non-abstract, and they read/write the non-tag components.  Not too
useful because there isn't any, but well-defined.

'Class'Read and 'Class'Write dispatch, so they never call the attributes
for an interface.  Fine.

'Input and 'Output behave much like 'Read and 'Write, 'cause there isn't
any discriminant to read/write.

'Class'Input and 'Class'Output read/write the tag of the parameter (which
is never the tag of an interface) and then dispatch.  Fine.

So I see no definitional problem here.

> I had just assumed that I could write:
>
> package P is
>
>    type I is interface;
>
>    package Ops is
>       function "="(Left, Right: I) return Boolean is
>       begin return Left'Address = Right'Address; end "="
>    end Ops;
>
> end P;
>
> It would be nice to be able to dispense with the package Ops,
> but now I
> am begining to wonder if there are any predefined operations or
> attributes for interface types.

The above is certainly legal, but the "=" is not primitive and hence not
inherited.  It can only be called explicitly using view conversions.

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

From: Robert I. Eachus
Sent: Wednesday, May 11, 2005  2:10 PM

>The above is certainly legal, but the "=" is not primitive and hence not
>inherited.  It can only be called explicitly using view conversions.

Understood.  I don't know why this misfeature is required (I must
declare a non-primitive "="), but it is.   Yes, I know that it would
'cause problems' if a derived type inherited two non-abstract
subprograms with the same signature.  I just think that requiring such
subprograms to be overridden--i.e. make them abstract--would be much
more user friendly.

However, what I was getting at in the example was that I should be able
to (and I can) write subprogram definitions that take parameters of the
interface type, and use attirbutes and subprograms with that notation
(such as Inf'Read) inside the subprogram body.   This rule means that I
will have to write 'wrappers' to make the calls look reasonable, but at
least I can have an interface that results in *one* copy of the actual
algorithm.

I can write a package that provides a sort routine through inheritance?

package Quicksort is

  type Sortable is interface;

  package Ops is
    function ">"(L,R: Sortable) return Boolean;
  end Ops;

  generic
    type Index is (<>);
    type Element is private;
    type To_Be_Sorted is new Sortable;
    with function Indexed_Element(S: To_Be_Sorted; I: Index) return Element;
    with procedure Set_Element(To: Element; S: in out To_Be_Sorted; I: Index);
  procedure Sort(Arr: in out To_Be_Sorted);

end Quicksort;

Not too painful, and I hope legal.  Hmmm.  The more elegant approach may be:

package Sortable_Arrays is
  type Element is interface;
  type Array_Of is array (Integer range <>) of Element'Class;
  generic
    with function ">"(L,R: Element) return Boolean;
  procedure Sort(Arr: in out Array_Of);
end Sortable_Arrays;

But I have a suspicion that even if this 'works' there will be too much
unnecessary tag checking to be efficient.   We then come full circle to:

generic
  type Element is private;
  with function ">"(L,R: Element) return Boolean;
package Sortable_Arrays is
  type Array_Of is array (Integer range <>) of Element;
  procedure Sort(Arr: in out Array_Of);
end Sortable_Arrays;

(Add a generic index parameter if you like.)

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

From: Randy Brukardt
Sent: Wednesday, May 11, 2005  5:50 PM

...
> Understood.  I don't know why this misfeature is required (I must
> declare a non-primitive "="), but it is.

Probably because it makes no sense to declare a concrete operation for a
type with no components or objects. What useful could you possibly write in
the body?

> Yes, I know that it would
> 'cause problems' if a derived type inherited two non-abstract
> subprograms with the same signature.  I just think that requiring such
> subprograms to be overridden--i.e. make them abstract--would be much
> more user friendly.
>
> However, what I was getting at in the example was that I should be able
> to (and I can) write subprogram definitions that take parameters of the
> interface type, and use attirbutes and subprograms with that notation
> (such as Inf'Read) inside the subprogram body.   This rule means that I
> will have to write 'wrappers' to make the calls look reasonable, but at
> least I can have an interface that results in *one* copy of the actual
> algorithm.

You can write such things, but IMHO they're always wrong. A non-primitive
operation on a tagged type should have parameters of the appropriate
class-wide type almost all of the time. That should be true in any case
where allowing extensions of the type are expected. The exceptions to this
rule are for cases like constructors, where extensions are discouraged or
(as for function results) impossible.

(The notion that 'Class has something to do with dispatching is one of
largest dis-services done to Ada 95 users. It's all about extensions; yes,
you need something class-wide to get dispatching, but it has many uses that
have nothing to do with dispatching.)

So, any such operation for interfaces (for which you cannot have
constructors) should have 'Class as its arguments. We don't make using
specific interfaces illegal because we don't want to deal with the generic
contract problems that that would cause, but there is no reason to ever do
it.

> I can write a package that provides a sort routine through inheritance?

Of course.

> package Quicksort is
>
>   type Sortable is interface;
>
>   package Ops is
>     function ">"(L,R: Sortable) return Boolean;
>   end Ops;

This makes no sense. Sortable has no components, so how could you
meaningfully write a body for it. It is the users of this interface that
have to provide the body.

>   generic
>     type Index is (<>);
>     type Element is private;
>     type To_Be_Sorted is new Sortable;
>     with function Indexed_Element(S: To_Be_Sorted; I: Index) return
Element;
>     with procedure Set_Element(To: Element; S: in out To_Be_Sorted; I:
Index);
>   procedure Sort(Arr: in out To_Be_Sorted);
>
> end Quicksort;

So I'd write this package like:

package Quicksort is

  type Sortable is interface;
  function ">" (Left, Right : Sortable) return Boolean is abstract;

   generic
     type Index is (<>);
     type Element is private;
     type To_Be_Sorted is new Sortable;
     with function Indexed_Element(S: To_Be_Sorted; I: Index) return
Element;
     with procedure Set_Element(To: Element; S: in out To_Be_Sorted; I:
Index);
   procedure Sort(Arr: in out To_Be_Sorted);

end Quicksort;

Except that it doesn't make sense to separate Sortable and the element type.
So I'd suggest something like:

package Quicksort is

  type Sortable is interface;
  function ">" (Left, Right : Sortable) return Boolean is abstract;

  generic
    type Index is (<>);
    type Sortable_Element is new Sortable;
    with function Indexed_Element(I: Index) return Element;
    with procedure Set_Element(To: Element; I: Index);
  procedure Sort;

end Quicksort;

But I'd really rather make this generic on the array type:

package Quicksort is

  type Sortable is interface;
  function ">" (Left, Right : Sortable) return Boolean is abstract;

  generic
    type Index is (<>);
    type Sortable_Element is new Sortable;
    type Sorted_Array is (Index) of Sortable_Element;
  procedure Sort (Arr: in out Sorted_Array);

end Quicksort;

But all of these interface solutions suffer from the fundamental failing of
Interfaces: you can only have one copy of the interface (and, worse, only a
specified name for the routine). So to allow differ sort orders, you'd have
to build that into the Sorting procedure, since you can't build it into the
interfaces. And you really don't want people to have to define a nonsense
">" just so sorting works (because lots of other stuff would fail). So it
would be best to avoid using the name ">" here. And perhaps best to just
stick with a generic sort. (Especially since one comes with Ada 2006. :-)

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

From: Robert I. Eachus
Sent: Wednesday, May 11, 2005  7:38 PM

>>Understood.  I don't know why this misfeature is required (I must
>>declare a non-primitive "="), but it is.
>
>Probably because it makes no sense to declare a concrete operation for a
>type with no components or objects. What useful could you possibly write in
>the body?

An algorithm that 'makes sense'  once the (abstract or null) are
overridden by operations for the type that inherits from the interface.

>You can write such things, but IMHO they're always wrong. A non-primitive
>operation on a tagged type should have parameters of the appropriate
>class-wide type almost all of the time. That should be true in any case
>where allowing extensions of the type are expected. The exceptions to this
>rule are for cases like constructors, where extensions are discouraged or
>(as for function results) impossible.

Or as in one of my examples, where you want to *avoid *tag checks and
dispatching.

>>package Quicksort is
>>
>>  type Sortable is interface;
>>
>>  package Ops is
>>    function ">"(L,R: Sortable) return Boolean;
>>  end Ops;
>>
>>
>
>This makes no sense. Sortable has no components, so how could you
>meaningfully write a body for it. It is the users of this interface that
>have to provide the body...
>
>So I'd write this package like:
>
>package Quicksort is
>
>  type Sortable is interface;
>  function ">" (Left, Right : Sortable) return Boolean is abstract;

You are right, that is much better in this case, I was focusing on the
situation I described above, where you can have a meaningful body in
terms of other primitives.  For a non-realistic example:

function ">" (Left, Right: Sortable) return Boolean is
begin return Right < Left; end ">";

Obviously this would be a bad thing to inherit.  I was thinking more in
terms of algorithms like Runge-Kutta, Fast Fourier Transform, etc.

>But all of these interface solutions suffer from the fundamental failing of
>Interfaces: you can only have one copy of the interface (and, worse, only a
>specified name for the routine). So to allow differ sort orders, you'd have
>to build that into the Sorting procedure, since you can't build it into the
>interfaces. And you really don't want people to have to define a nonsense
>">" just so sorting works (because lots of other stuff would fail). So it
>would be best to avoid using the name ">" here. And perhaps best to just
>stick with a generic sort. (Especially since one comes with Ada 2006. :-)

I was using Sort as a strawman.  One of the problems that I have with
Ada today is trying to abstract algorithms from type specific code, so
that you don't have to maintain several versions of the same algorithm.
Unfortunately generics don't work, because you want Integer, Float, and
Fixed versions--and sometimes Unsigned as well.  Yes, there are some
cases where this is just not possible--code for fixed and floating
matrix inversion needs to be very different.  But there are a few where
you end up with two or more variables and a result that may be any of
the three types.  (Well, I'm thinking mostly of distribution functions
in statistics, the result domain is usually well defined as to type--for
a particular distribution.  But there are cases where I should allow
both float and fixed probabilities.)

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

From: Randy Brukardt
Sent: Wednesday, May 11, 2005  9:09 PM

...
> >Probably because it makes no sense to declare a concrete operation for a
> >type with no components or objects. What useful could you possibly write in
> >the body?
> >
> >
> An algorithm that 'makes sense'  once the (abstract or null) are
> overridden by operations for the type that inherits from the interface.

OK, but to get to the overridden routines, you need dispatching. And to get
dispatching, you want the parmeters to your operation to be class-wide. So,
I ask again, what useful code could you write in the body of an operation
with *specific* interface parameters?

...
> Or as in one of my examples, where you want to *avoid *tag checks and
> dispatching.

If you want to avoid dispatching, you can't use interfaces. They *only* work
through dispatching. That's different than regular abstract types, which can
have components and thus useful concrete operations.

But really, dispatching is so cheap that it is silly to try to avoid it. The
only valid reason is the use of tools that don't support it (like SPARK),
and there I think the tools should be improved. You'd be better off avoiding
generics (at least if you are using Janus/Ada) or discriminants controlling
arrays.

...
> You are right, that is much better in this case, I was focusing on the
> situation I described above, where you can have a meaningful body in
> terms of other primitives.  For a non-realistic example:
>
> function ">" (Left, Right: Sortable) return Boolean is
> begin return Right < Left; end ">";

This is illegal, since "<" is necessarily abstract (functions can't be
null), and thus cannot be called except in a dispatching call. (That makes
it even more unrealistic than you had supposed. :-) If you had written:

function ">" (Left, Right: Sortable'Class) return Boolean is
begin return Right < Left; end ">";

This would work fine, but then we wouldn't be having this conversation. :-)

...
> I was using Sort as a strawman.  One of the problems that I have with
> Ada today is trying to abstract algorithms from type specific code, so
> that you don't have to maintain several versions of the same algorithm.
> Unfortunately generics don't work, because you want Integer, Float, and
> Fixed versions--and sometimes Unsigned as well.  Yes, there are some
> cases where this is just not possible--code for fixed and floating
> matrix inversion needs to be very different.  But there are a few where
> you end up with two or more variables and a result that may be any of
> the three types.  (Well, I'm thinking mostly of distribution functions
> in statistics, the result domain is usually well defined as to type--for
> a particular distribution.  But there are cases where I should allow
> both float and fixed probabilities.)

True enough. There seem to be examples where Interfaces work fine. As long
as the operations are well-defined and don't potentially conflict with
normal practice. I usually use the queuing example as a strawman, since it
is a much better fit for interfaces.

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


Questions? Ask the ACAA Technical Agent