Version 1.3 of ais/ai-00443.txt

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

!standard 3.9.4(1)          05-12-14 AI95-00443/01
!standard 7.3(3)
!standard 7.3(6)
!standard 7.3(8)
!standard 12.5.1(3)
!standard 12.5.1(5)
!standard 12.5.1(5.1)
!class Amendment 05-12-14
!status Amendment 200Y 06-01-04
!status WG9 Approved 06-06-09
!status work item 05-12-11
!status received 05-12-11
!subject Synchronized private extensions
!summary
(See recommendation.)
!question
Synchronized interfaces are one of the "crown jewels" of Ada 2005. But it seems inconsistent that "limited" is not inherited from interfaces, but instead must be respecified on the derived type, while synchronized is inherited, and in fact cannot be specified on a private extension. Furthermore, if a full type is synchronized, but has no synchronized interface ancestor, you can't create a partial view of it without adding an otherwise unnecessary synchronized interface.
Note that neither limited nor synchronized is inherited by interfaces, but instead both must be respecified explicitly. So it seems odd that for the one case of private extensions, "synchronized" is inherited.
Although this is late in the game, these awkward and inconsistent rules for inheritance of synchronized will be hard to fix later, as there will be upward compatibility issues to worry about at some later date.
!recommendation
Allow a private extension to be specified explicitly as "synchronized" rather than "limited," and eliminate the inheritance of "synchronized" from interfaces under all circumstances.
SImilarly, formal private extensions could be specified as synchronized.
!wording
Modify 3.9.4(6) as follows:
A task or protected type derived from an interface is a tagged type. Such a tagged type is called a synchronized tagged type, as are synchronized interfaces and private extensions [derived from synchronized interfaces] {whose declaration includes the reserved word synchronized}.
AARM NOTE: "Private extensions" includes formal private extensions, per 12.5.1.
Change 7.3(3) to be:
private_extension_declaration ::= type defining_identifier [discriminant_part] is [abstract] [limited | synchronized] new ancestor_subtype_indication [and interface_list] with private;
Modify 7.3(6) as follows:
A private type is limited if its declaration includes the reserved word limited; a private extension is limited if its ancestor type is a limited type that is not an interface type, or if the reserved word limited {or synchronized} appears in its definition. If the partial view is nonlimited, then the full view shall be nonlimited. If a tagged partial view is limited, then the full view shall be limited. On the other hand, if an untagged partial view is limited, the full view may be limited or nonlimited.
Modify the paragraph added after 7.3(8) by AI-419 as follows:
If the reserved word limited appears in a private_extension_declaration, the ancestor type shall be a limited type. {If the reserved word synchronized appears in a private_extension_declaration, the ancestor type shall be a limited interface.}
Change 12.5.1(3) to be:
formal_derived_type_definition ::= [abstract] [limited | synchronized] new subtype_mark [[and interface_list] with private]
Modify 12.5.1(5) as follows:
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{s} abstract {or synchronized} shall appear only if the ancestor type is a tagged type. {[Finally, t] {T}he reserved word{s} limited {or synchronized} shall appear only if the ancestor type and any progenitor types are limited types. {The reserved word synchronized shall appear (rather than limited) if the ancestor type or any of the progenitor types are synchronized interfaces.}
Modify the paragraph added after 12.5.1(5) by AI-251 and modified by AI-401 as follows:
The actual type for a [generic] formal derived type shall be a descendant of {Redundant[the ancestor type] and} every progenitor of the formal type. {If the reserved word synchronized appears in the declaration of the formal derived type, the actual type shall be a synchronized tagged type.}
AARM NOTE: For a non-formal private extension, we require the partial
view to be synchronized if the full view is synchronized tagged. This does not apply to a formal private extension -- it is OK if the formal is not synchronized. Any attempt to extend the formal type will be rechecked in the instance, where the rule disallowing extending a sychronized non-interface type will be enforced. This is consistent with the "no hidden interfaces" rule also applying only to non-formal private extensions, as well as the rule that a limited non-formal private extension implies a limited full type. Formal private extensions are exempted from all these rules to enable the construction of generics that can be used with the widest possible range of types. In particular, an indefinite tagged limited formal private type can match any "concrete" actual tagged type.
!discussion
During implementation it was noticed that limitedness is not inherited by a private extension from the ancestor if it is limited, while synchronized is inherited from any interface ancestor. That seems a inconsistent. It might be friendlier to say:
A private extension is limited if
a) its parent is a non-interface limited type b) its parent or any progenitor is a synchronized interface c) the reserved word "limited" appears
Alternatively it would be even more consistent if synchronized is not inherited, and instead require there be an explicit use of "synchronized" in place of "limited" in front of "new" if the parent or any progenitor is synchronized. E.g.:
type Private_Task is synchronized new Task_Intf with private;
The current situation, where synchronized is inherited by private extensions, but you must write limited (rather than "synchronized") whenever that happens, seems like the worst of both worlds.
There is another problematic rule we should relate to this, namely that if a full view is synchronized, then the partial view must be as well. This rule is necessary because doing a record extension on the partial view is not permitted if it is synchronized. It is problematic because there is no way to declare the partial view as synchronized, except by forcing it to have a synchronized interface ancestor. But such a requirement doesn't apply to the full view, since a task or protected type can be derived from just a limited interface.
What this means is that if you want to create a partial view of a tagged task or protected type, you have to first make sure it has at least one synchronized interface ancestor.
For example:
type Lim_Intf is limited interface;
type Private_Task is limited new Lim_Intf with private; -- illegal!
private
task type Private_Task is new Lim_Intf with entry E1; end Private_Task;
-------- The above is illegal by 7.3(7.2/2), because the full view is a synchronized tagged type and the partial view is not. The only way to fix this is to create a bogus synchronized interface, and add it to the interface list for both the partial view and the full view. That seems a little awkward.
Simpler for the user would be to allow the use of "synchronized" rather than "limited" for the private extension. It would also be better for the reader, as the word synchronized would be visible, rather than being inherited from some interface. We have decided that limited is not inherited from interfaces; it seems confusing then that synchronized can only be inherited from an interface -- there is no way to state it explicitly for a private extension. On the other hand, synchronized is not inherited by interfaces.
This dilemma argues for the second alternative, namely allowing the use of an explicit "synchronized" instead of "limited" in front of "new."
Thus we solve both problems identified above by saying that a private extension does not inherit either limitedness or synchronizedness from its interface ancestors, but instead, either of these must be specified explicitly if you want them (and you surely do if you have any synchronized interface ancestors, or if the full type is synchronized).
Hence the syntax for private extensions would become:
type defining_identifier [discriminant_part] is
[abstract] [limited | synchronized] new ...
and only the private extensions with the reserved word "synchronized" in their definitions would be synchronized tagged types. This would simplify the story for synchronized tagged types so that they always have "synchronized", "protected", or "task" in their definition.
One additional possibility considered was to further extend the syntax to allow the words "task" or "protected." But there seems no real justification for that. Furthermore "... task new T" and "... protected new T" read badly, and "task" and "protected" seem like a bit "too much information" for a private extension. Why not just make the task or protected type non-private at that point?
Furthermore, there is no particular need to identify a private extension as task or protected. The only additional operation that would be gained for a task would be "abort," but this is easily enough provided by an additional primitive operation in the rare case that abort from outside the package is desirable. No additional operation would be gained with "protected." On the other hand, by allowing "synchronized," we can make it clear that further record extensions are not permitted, which is the crucial piece of information from a legality rule point of view, while also promising that the type is "thread-safe," which is extremely relevant from a usage point of view.
Finally, it could be confusing that task types have the word "task" first whereas task private extensions would have the word in the middle.
task type TT is ...
vs.
type PTT is task new TIF with private;
seems quite inconsistent. There is no corresponding confusion with "synchronized." And the "task new" sequence is really awkward grammatically, since "task" is not an adjective.
One alternative would be:
task type TT is new TIF with private;
But then we get into trouble with where "limited" goes vs. where task/protected go. In addition, with this syntax, there would be no justification for not allowing private task types:
task type TT is private;
which seems to be getting pretty far afield, and clearly seems more appropriate for consideration for 2015, if the value is really there.
No corresponding temptation exists for synchronized private types, because synchronized is only defined for tagged types, and:
type TT is tagged synchronized private;
would be illegal since the full type necessarily has at least one interface ancestor, which must be exposed in any partial view.
Bottom line is that "synchronized" is an interesting abstract property, whereas "task" or "protected" are not very abstract, and you might as well just expose the type declarations themselves at that point. You are not getting much additional "abstraction" when you have a private extension, if you advertise the fact that the full type is a task. You never see the internal data of a task anyway. And the entries are often going to correspond to exported operations. Note that with task interfaces you get polymorphism, which is useful. But you don't get polymorphism with private extensions; you only get abstraction and information hiding, and not enough of either to justify the additional syntax required for protected or task private extensions.
!example
type Lim_Intf is limited interface;
type Private_Task is synchronized new Lim_Intf with private; -- legal!
private
task type Private_Task is new Lim_Intf with entry E1; end Private_Task;
!comment The wording of AI-345 for 3.9.4 is omitted here; as a new section,
!comment we can't reference it. The changes are placed into the conflict file.
!comment We just put a dummy paragraph here:
!corrigendum 3.9.4(1)
Insert new clause:
An interface type is an abstract tagged type that provides a restricted form of multiple inheritance. A tagged, task, or protected type may have one or more interface types as ancestors.
!corrigendum 7.3(3)
Replace the paragraph:
private_extension_declaration ::= type defining_identifier [discriminant_part] is [abstract] new ancestor_subtype_indication with private;
by:
private_extension_declaration ::= type defining_identifier [discriminant_part] is [abstract] [limited | synchronized] new ancestor_subtype_indication [and interface_list] with private;
!corrigendum 7.3(6)
Replace the paragraph:
A private type is limited if its declaration includes the reserved word limited; a private extension is limited if its ancestor type is limited. If the partial view is nonlimited, then the full view shall be nonlimited. If a tagged partial view is limited, then the full view shall be limited. On the other hand, if an untagged partial view is limited, the full view may be limited or nonlimited.
by:
A private type is limited if its declaration includes the reserved word limited; a private extension is limited if its ancestor type is a limited type that is not an interface type, or if the reserved word limited or synchronized appears in its definition. If the partial view is nonlimited, then the full view shall be nonlimited. If a tagged partial view is limited, then the full view shall be limited. On the other hand, if an untagged partial view is limited, the full view may be limited or nonlimited.
!corrigendum 7.3(8)
Insert after the paragraph:
The ancestor subtype of a private_extension_declaration is the subtype defined by the ancestor_subtype_indication; the ancestor type shall be a specific tagged type. The full view of a private extension shall be derived (directly or indirectly) from the ancestor type. In addition to the places where Legality Rules normally apply (see 12.3), the requirement that the ancestor be specific applies also in the private part of an instance of a generic unit.
the new paragraph:
If the reserved word limited appears in a private_extension_declaration, the ancestor type shall be a limited type. If the reserved word synchronized appears in a private_extension_declaration, the ancestor type shall be a limited interface.
!corrigendum 12.5.1(3)
Replace the paragraph:
formal_derived_type_definition ::= [abstract] new subtype_mark [with private]
by:
formal_derived_type_definition ::= [abstract] [limited | synchronized] new subtype_mark [[and interface_list] with private]
!corrigendum 12.5.1(5)
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 words abstract or synchronized shall appear only if the ancestor type is a tagged type. The reserved word limited or synchronized shall appear only if the ancestor type and any progenitor types are limited types. The reserved word synchronized shall appear (rather than limited) if the ancestor type or any of the progenitor types are synchronized interfaces.
The actual type for a formal derived type shall be a descendant of the ancestor type and every progenitor of the formal type. If the reserved word synchronized appears in the declaration of the formal derived type, the actual type shall be a synchronized tagged type.
!ACATS test
Create B and C-Tests to check this syntax and semantics.
!appendix

From: Tucker Taft
Sent: Thursday, December  8, 2005 11:09 AM

We are implementing the rules for private extensions derived
from interfaces.  I noticed that limitedness is not inherited
from the ancestor if it is limited, while synchronized *is*
inherited from *any* interface ancestor.  That seems a bit
bizarre.  It would seem friendlier to say:

    A private extension is limited if
       a) its parent is a non-interface limited type
       b) its parent or any progenitor is a synchronized interface
       c) the reserved word "limited" appears

Alternatively we could say that synchronized is *not* inherited,
and require an explicit use of "synchronized" in place of "limited"
in front of "new" if the parent or any progenitor is synchronized.
E.g.:

    type Private_Task is synchronized new Task_Intf with private;

But this latter requires new syntax, which seems a bit much at this
stage.  Also, I suppose if you allow both limited and synchronized,
then we ought to allow "task" and "protected" as well to be consistent
with the syntax for interfaces, which really seems like a big change.

The current situation, where synchronized is inherited by private
extensions, but you *must* write limited whenever that happens,
seems like the worst of both worlds.

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

From: Tucker Taft
Sent: Thursday, December  8, 2005 11:31 AM

On further reflection, there is another weird rule we should
relate to this, namely that if a full view is synchronized,
then the partial view must be as well.  This rule is necessary
because doing a record extension on the partial view is
not permitted if it is synchronized.  It is weird because
there is no way to declare the partial view as synchronized,
except by forcing it to have a synchronized interface
ancestor.  But such a requirement doesn't apply to
the full view, since a task or protected type can be
derived from just a limited interface.

What this means is that if you want to create a partial view
of a tagged task or protected type, you have to first make
sure it has at least synchronized interface ancestor.

This dilemma argues for the second alternative, namely allowing
the use of an explicit "synchronized" instead of "limited" in
front of "new."  Despite my suggestion below that we would
naturally want to extend that to allow the words "task" or
"protected," there seems no real justification for that, and
"... task new T" and "... protected new T" read horribly, and
"task" and "protected" seem like a bit "too much information"
for a private extension.

Hence I guess I am now suggesting we could solve both weirdities by
saying that a private extension does *not* inherit either limitedness
or synchronizedness from its interface ancestors, but instead,
either of these must be specified explicitly if you want them
(and you surely *do* if you have any synchronized interface
ancestors, or if the full type is synchronized).

Hence the syntax for private extensions would become:

     type defining_identifier [discriminant_part] is
       [abstract] [limited | synchronized] new ...

and a synchronized tagged type would only include private extensions
with the reserved word "synchronized" in their definitions.
This would simplify the story for synchronized tagged types
so that they always have "synchronized", "protected", or "task"
in their definition.

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

From: Stephen Michell
Sent: Thursday, December  8, 2005 12:01 PM

Tucker's proposal seems to imply that it would be legal to derive from a
synchronized or limited interface and NOT implement by something which
satisfied the requirements of synchronized or limited. I would have a problem
with that situation. IMO, if limiteness and synchronized properties are not
inherited, then it must be the case that the derived entity must restate that
property.

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

From: Tucker Taft
Sent: Thursday, December  8, 2005  2:01 PM

The existing rules don't have the problem you fear, but they are
difficult to explain and do create the funny need to add a
"bogus" synchronized interface to a tagged task or protected
type to be able to create a private view of it.  I think
this would be the only case where there would be a
tagged type for which you could't create a tagged partial view
that represents it.

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

From: Randy Brukardt
Sent: Thursday, December  8, 2005  2:30 PM

I don't follow this. This issue only occurs for tagged task or protected
types, right? Now, since we don't allow extension of those, they have to
have one or more interfaces in order to be tagged. Because of the no-hidden
interfaces rule, the interfaces have to be given on the partial view. So,
the interfaces give the proper type to the partial view. What's the
problem??

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

From: Tucker Taft
Sent: Thursday, December  8, 2005  4:13 PM

Example:

     type Lim_Intf is limited interface;

     type Private_Task is limited new Lim_Intf with private;

   private

     task type Private_Task is new Lim_Intf with
         entry E1;
     end Private_Task;

--------
The above is illegal by 7.3(7.2/2), because the full view is
a synchronized tagged type and the partial view is not.
The only way to fix this is to create a bogus synchronized
interface, and add it to the interface list for both the
partial view and the full view.  That seems a little weird.

Simpler for the user would be to allow the use of "synchronized"
rather than "limited" for the private extension.  It would
also be better for the reader, as the word synchronized would
be visible, rather than be inherited from some interface.
We have decided that limited is not inherited from interfaces;
it seems confusing then that synchronized can *only* be inherited
from an interface -- there is no way to state it explicitly
for a private extension.

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  3:18 PM

I think it is too late to make any substantial change in this
area. I don't think the problem is sufficiently severe to warrant
changing the established (and already in use) rules.

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

From: Pascal Leroy
Sent: Friday, December  9, 2005  4:06 AM

Tuck proposed:
> Hence the syntax for private extensions would become:
>
>      type defining_identifier [discriminant_part] is
>        [abstract] [limited | synchronized] new ...
>
> and a synchronized tagged type would only include private
> extensions with the reserved word "synchronized" in their
> definitions. This would simplify the story for synchronized
> tagged types so that they always have "synchronized",
> "protected", or "task" in their definition.

If you went that way, you would definitely want to allow "task" and
"protected" in the syntax above.  By your reasoning, you don't want to
force users to declare a task interface if they want to expose the
task-ish nature of a private extension.

Note that in your example:

     type Lim_Intf is limited interface;

     type Private_Task is limited new Lim_Intf with private;
   private
     task type Private_Task is new Lim_Intf with
         entry E1;
     end Private_Task;

all you have to do is declare a synchronized intermediate:

     type Lim_Intf is limited interface;
     type Sync_Intf is synchronized and Lim_Intf;
     type Private_Task is limited new Sync_Intf with private;

And one could in fact argue that it is a good thing from the
methodological standpoint to reify the synchronized interface.  So I tend
to think that it is not badly broken, and that it comes late in the day
anyway.

However I want to make sure that synchronized interfaces "work right", so
I am willing to give some consideration to your proposal.  One reason that
is that it changes the syntax, so it's not something that we'll be willing
to sneak in an Ada 2005 AI.

In order to evaluate the impact of this idea on the RM and on
implementations, we need words *really quick*.  So you are hereby tasked
to write an AI, preferably before close of business CET today, that
contains the necessary wording changes.

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

From: Tucker Taft
Sent: Wednesday, December 14, 2005  8:03 AM

Here is an AI that has been reviewed by Randy,
Pascal, and John.  [This is version /01 of the AI - ED]
It addresses the current
inconsistency in the rules relating to how
"synchronized-ness" is inherited, where for
interfaces it is *not* inherited from other
interfaces, but for private extensions, it
*is* inherited from any interface ancestor,
and in fact can't be specified explicitly.
By contrast, "limited-ness" is not inherited
by private extensions from their interface
ancestors, and *must* be specified explicitly
if it is desired.

There are two implications of this inconsistency
which this AI explains, and ultimately the AI comes to
the conclusion that we should eliminate this
inheritance of "synchronized" and instead
allow/require it to be respecified as with
"limited" for private extensions, hence:

    type Synch_T is synchronized new Lim_Intf with private;

would be the syntax when defining a private extension
representing a partial view of a synchronized tagged type.

Unfortunately this is not something that can easily be
delayed to a future revision of the standard, as these
inheritance rules will be very difficult to change later
without incurring significant upward incompatibility.

This AI will be forwarded via the US delegation to WG9
pending comments by the ARG.

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


Questions? Ask the ACAA Technical Agent