!standard 3.09 (06) 06-02-01 AI95-00260-02/09
!standard 3.09 (07)
!standard 3.09 (12)
!standard 3.09 (18)
!standard 3.09 (25)
!standard 3.09 (26)
!standard 3.09 (30)
!standard 3.09.02 (01)
!standard 3.09.02 (02)
!standard 3.09.02 (22)
!standard 3.09.03 (03)
!standard 3.09.03 (11)
!standard 12.06 (02)
!standard 12.06 (04)
!standard 12.06 (08)
!standard 12.06 (10)
!standard 12.06 (16)
!class amendment 04-09-08
!status Amendment 200Y 04-12-01
!status WG9 Approved 06-06-09
!status ARG Approved 9-0-1 04-11-19
!status work item 04-09-08
!status received 04-09-08
!priority Medium
!difficulty Medium
!subject Abstract formal subprograms and dispatching constuctors
!summary
A new kind of generic formal subprogram, the abstract formal subprogram, is
defined. It allows the importation of dispatching operations into a generic
unit.
A pair of generic units are defined to allow dispatching to a routine with a
controlling result. This unit makes it possible to write functions with similar
semantics to T'Class'Input, including a complete replacement for the function.
An operation is defined in Ada.Tags to get the tag of a parent type.
!problem
S'Class'Output writes the tag of an item with String'Output. This routine
cannot be replaced, so it is not possible to write the tag in an arbitrary
user-defined format (to match an external standard, for example).
Consider, for example, XML, which is a text format. With the current
language definition, it is not possible to redefine the 'Read and 'Write
attribute to have the object streamed as an XML object. This is surprising,
as external tags are defined as strings. It is possible to change the external
tag string value by using Ada.Tags facilities. But the tag will always
be streamed as an object of type String. This means that the tag string value
will be written preceded by the string bounds -- which are binary data. There
is no way to prevent this binary data from being sent. In other words, there
is no way to stream an object with a plain text representation.
!proposal
(See wording.)
!wording
Add after 3.9(6):
No_Tag : constant Tag;
Add after 3.9(7):
function Parent_Tag (T : Tag) return Tag;
Add after 3.9(9):
No_Tag is the default initial value of type Tag.
Add after 3.9(12):
The function Parent_Tag returns the tag of the parent type of the type whose
tag is T. If the type does not have a parent type (that is, it was not
declared by a derived_type_declaration), then No_Tag is returned.
AARM Note: The parent type is always the parent of the full type; a private
extension appears to define a parent type, but it does not (only the various
forms of derivation do that). As this is a run-time operation, ignoring
privateness is OK.
Add after 3.9(18):
The following language-defined generic function exists:
generic
type T (<>) is abstract tagged limited private;
type Parameters (<>) is limited private;
with function Constructor (Params : access Parameters)
return T is abstract;
function Ada.Tags.Generic_Dispatching_Constructor
(The_Tag : Tag;
Params : access Parameters) return T'Class;
pragma Preelaborate(Generic_Dispatching_Constructor);
pragma Convention(Intrinsic, Generic_Dispatching_Constructor);
Tags.Generic_Dispatching_Constructor
provides a mechanism to create an object of an appropriate type from just a tag
value. The function Constructor is expected to create the object given a
reference to an object of type Parameters.
AARM Notes: This specification is designed to make it easy to create
dispatching constructors for streams; in particular, this can be used to
construct overridings for T'Class'Input.
Note that any tagged type will match type T (see 12.5.1).
End AARM Notes.
Add after 3.9(25):
Tag_Error is raised by a call of Expanded_Name, External_Tag, or Parent_Tag if
any tag passed is No_Tag.
[Editor's Note: If AI-344 is included in the Amendment, this rule should
include Descendant_Tag and Is_Descendant_At_Same_Level.]
An instance of Tags.Generic_Dispatching_Constructor raises Tag_Error if
The_Tag does not represent a concrete descendant of T or if the
innermost master (see 7.6.1) of this descendant is not also a master of the instance.
Otherwise, it dispatches to the primitive function denoted by the formal
Constructor for the type identified by The_Tag, passing Params, and
returns the result. Any exception raised by the function is propagated.
AARM Note (Ramification): The tag check checks both that The_Tag is in T'Class,
and that it is not abstract. These checks are similar to the ones required by
streams for T'Class'Input (see 13.13.2). [Note to readers, these are found in
AI-279.]
Erroneous Execution
If an internal tag provided to an instance of
Tags.Generic_Dispatching_Constructor or to any subprogram declared in package
Tags identifies either a type that is not library-level and whose tag has not
been created (see 13.14), or a type that does not exist in the partition at the
time of the call, then execution is erroneous.
AARM Note: We exclude tags of library-level types from the current
execution of the partition, because misuse of such tags should always be
detected. T'Tag freezes the type (and thus creates the tag), and Internal_Tag
and Descendant_Tag cannot return the tag of a library-level type that has not
been created. Finally, library-level types never cease to exist while the
partition is executing. Thus, if the tag comes from a library-level type, there
cannot be erroneous execution (the use of Descendant_Tag rather than
Internal_Tag can help insure that the tag is of a library-level type). This is
also similar to the rules for T'Class'Input (see 13.13.2). [Note to readers,
this also is found in AI-279.]
Replace 3.9(26) by:
The implementation of Internal_Tag and Descendant_Tag may raise Tag_Error if no
specific type corresponding to the string External passed as a parameter exists
in the partition at the time the function is called, or if there is no such
type whose innermost master is a master of the point of the function call.
Implementation Advice
Internal_Tag should return the tag of a type whose innermost master is the
master of the point of the function call.
Add after 3.9(30):
The capability provided by Tags.Generic_Dispatching_Constructor is
sometimes known as a factory.
Change the first sentence of 3.9.2(1):
The primitive subprograms of a tagged type and the
subprograms declared by formal_abstract_subprogram_declarations
are called *dispatching operations*.
Change the first sentence of 3.9.2(2):
A *call on a dispatching operation* is a call whose name or prefix denotes the
declaration of a dispatching operation.
Change "primitive" to "dispatching" in 3.9.2(22).
Change the first sentence of 3.9.3(3):
A subprogram declared by an abstract_subprogram_declaration (see 6.1) or
a formal_abstract_subprogram_declaration (see 12.6) is an abstract
subprogram.
Replace the first sentence of 3.9.3(11) by:
A generic actual subprogram shall not be an abstract subprogram unless the
generic formal subprogram is declared by a
formal_abstract_subprogram_declaration.
Replace 12.6(2) by:
formal_subprogram_declaration ::= formal_concrete_subprogram_declaration
| formal_abstract_subprogram_declaration
formal_concrete_subprogram_declaration ::=
with subprogram_specification [is subprogram_default];
formal_abstract_subprogram_declaration ::=
with subprogram_specification is abstract [subprogram_default];
Add after 12.6(8):
If a formal parameter of a formal_abstract_subprogram_declaration is of a
specific tagged type T or of an anonymous access type designating a specific
tagged type T, T is called a controlling type of the
formal_abstract_subprogram_declaration. Similarly, if the result of a
formal_abstract_subprogram_declaration for a function is of a specific tagged
type T or of an anonymous access type designating a specific tagged type T,
T is called a controlling type of the formal_abstract_subprogram_declaration. A
formal_abstract_subprogram_declaration shall have exactly one controlling type.
AARM Notes:
The specific tagged type could be any of a formal tagged private type,
a formal derived type, or a normal tagged type. While the last case doesn't
seem to be very useful, there isn't any good reason for disallowing it.
This rule insures that the operation is a dispatching operation of some
type, and that we unambiguously know what that type is.
We informally call a subprogram declared by
a formal_abstract_subprogram_declaration an *abstract formal subprogram*,
but we do not use this term in normative wording.
[Editor's note: This is so that it is indexed in the AARM (not the RM), and it
gives an ordering for the two modifiers.]
End AARM Notes.
The actual subprogram for a formal_abstract_subprogram_declaration shall be a
dispatching operation of the controlling type or of the actual type
corresponding to the controlling type.
AARM Note:
To Be Honest: We mean the controlling type of the
formal_abstract_subprogram_declaration, of course. Saying that gets unwieldy
and redundant.
This means that it is either a primitive operation of the
controlling type, or an abstract formal subprogram. Also note that this
prevents the controlling type from being class-wide,
as only specific types have primitive operations (and a formal subprogram
eventually has to have an actual that is a primitive of some type). This could
happen in a case like:
generic
type T(<>) is tagged private;
with procedure Foo (Obj : in T) is abstract;
package P ...
package New_P is new P (Something'Class, Some_Proc);
The instantiation here is always illegal, because Some_Proc could never be
a primitive operation of Something'Class (there are no such operations). That's
good, because we want calls to Foo always to be dispatching calls.
End AARM Note.
Add after 12.6(10):
The subprogram declared by a formal_abstract_subprogram_declaration with a
controlling type T is a dispatching operation of type T.
AARM Note:
This is necessary to trigger all of the dispatching operation
rules. It otherwise would not be considered a dispatching operation, as
formal subprograms are never primitive operations.
Replace 12.6(16) by:
18 The actual subprogram cannot be abstract unless the formal
subprogram is a formal_abstract_subprogram_declaration (see 3.9.3).
Add a new note after 12.6(16):
19 The subprogram declared by a formal_abstract_subprogram_declaration
is an abstract subprogram. All calls on a subprogram declared by a
formal_abstract_subprogram_declaration must be dispatching calls. See 3.9.3.
[Editor's Note: These things are defined in 3.9.3, but they are important to
mention here.]
!discussion
A function like the instance of Generic_Dispatching_Constructor or
T'Class'Input is often called a "factory" in OOP literature. Factories can be
useful in scenarios other than streaming. See the examples for two possible
uses.
The only part of T'Class'Input that cannot be written in Ada is the dispatching
call to T'Input. This is the part that we need to model with a built-in
operation. It's not necessary to create an object of the type; the called
function will do that. That avoids problems with discriminants which aren't
known.
Adding a new kind of generic formal for this problem is somewhat heavy.
However, such a formal would be useful in other cases than this generic;
Ada 95 has no way to define a dispatching generic formal. For instance,
consider a generic that implemented a persistence add-in. If it had
flattening/reconstruction formals that were dispatching, then a single
instantiation could add persistence to an entire type hierarchy. (And this
could be done without constraining the names of the subprograms or modifying
the base class, as the use of interfaces would require.) The implementation
of abstract formal subprograms is easy (it presumably would pass the slot
number of the call for a sharing implementation).
We need separate limited and nonlimited versions of this generic, because
nonlimited tagged types do not match limited tagged formal types. The
limited version requires the definition of functions returning limited types
as expressed by AI-318-2/06.
---
The Parent_Tag operation makes available to the user information that the
compiler must have in order to do type conversion and membership checks.
---
An alternative considered was to use an interface to define the profile of
a constructor. This could look like:
with Ada.Tags;
generic
type Parameters (<>) is limited private;
package Ada.Generic_Dispatching_Construction is
type Constructed is limited interface;
function Constructor (Params : access Parameters)
return Constructed is abstract; -- primitive op
function Dispatching_Constructor
(Tag : Ada.Tags.Tag;
Params : access Parameters)
return Constructed'Class; -- not a primitive op
end Ada.Generic_Dispatching_Construction;
with Ada.Streams;
with Ada.Generic_Dispatching_Constructor;
package Ada.Streaming_Construction is new
Ada.Generic_Dispatching_Construction (
Parameters => Ada.Streams.Root_Stream_Type'Class);
Dispatching_Constructor raises Tag_Error if Tag does not represent a
concrete descendant of Constructed. Otherwise, Dispatching_Constructor
dispatches to the version of Constructor for the type identified by
the tag Tag, passing Params, and returns the result.
The advantage of this is that no new kind of generic formal subprogram is
needed.
However, this solution has several minor problems and one significant one.
With apologies to David Letterman, here are the top 4 reasons that this
isn't the best solution:
4) This cannot be used to describe the semantics of T'Class'Input. That
means the rules of AI-279 have to be duplicated in both the constructor
and the description of T'Class'Input. (They're fairly short, though, and
we did that anyway).
3) To use this to redefine T'Class'Input, the base class has to be
modified to add this interface.
2) The constructor function has to be named Constructor. A more appropriate
name cannot be used.
And the number one reason that this is not the best solution:
1) This only allows one instance of a dispatching constructor per type
hierarchy. (That's because of (2): there is only one name for the
Constructor function.) It would be possible to use T'Class'Input
in addition to this constructor. But the point of adding this generic
is to allow users to create this sort of functionality when it is
needed. Allowing only a single instance of it is hardly any better than
the current situation where the only way to get this functionality is
to hijack T'Class'Input. The solution should not limit the number
of factories that can be created for a given type hierarchy.
---
This is presented as an alternative to the Tag_Read and Tag_Write attributes.
It would be possible to support both, but there doesn't seem to be any strong
need to do so. As shown below, with this proposal overriding T'Class'Input
and T'Class'Output is no more difficult than implementing Tag_Read and
Tag_Write.
In addition, AI-344 forces the specification of Tag_Read to be:
function S'Class'Tag_Read (
Stream : access Streams.Root_Stream_Type'Class;
Ancestor : Ada.Tags.Tag) return Ada.Tags.Tag;
as the ancestor parameter is necessary to implement the default functionality.
However, it would rarely (if ever) be useful in an overridden implementation.
And this makes Tag_Read and Tag_Write less symmetrical. Also note that the
complete replacement approach means that we don't have to specify "shoulds"
about the behavior of the attributes; whatever the user writes is what it will
do, and if that doesn't make sense it is the user's problem.
!example
Here is an example that illustrates the problem. Suppose that we want to
stream an object with an XML encoding:
with Ada.Streams;
package Class is
type Object is tagged record
V : Integer := 2;
end record;
procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
O : Object);
for Object'Write use Write;
for Object'External_Tag use "");
end Write;
end Class;
with Ada.Text_IO.Text_Streams;
with Class;
procedure Main is
O : Class.Object;
begin
Class.Object'Class'Output
(Ada.Text_IO.Text_Streams.Stream (Ada.Text_IO.Current_Output), O);
end Main;
This program output will be something like:
^A^@^@^@^H^@^@^@
The first 8 bytes (characters) are the binary representation for the tag bound.
In Ada 95, there is no way to prevent these bytes from being written, so
there is no way to stream an object with an XML representation.
Using Generic_Dispatching_Constructor, it is possible to override
T'Class'Input and T'Class'Output to read/write the proper format.
with Ada.Streams, Ada.Tags;
package Class is
type Object is tagged record
V : Integer := 2;
end record;
for Object'External_Tag use "object";
procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
O : Object);
for Object'Write use Write;
procedure Class_Output (S : access Ada.Streams.Root_Stream_Type'Class;
O : Object'Class);
for Object'Class'Output use Class_Output;
function Class_Input (S : access Ada.Streams.Root_Stream_Type'Class)
return Object'Class;
for Object'Class'Input use Class_Input;
end Class;
with Ada.Tags.Generic_Dispatching_Constructor;
package body Class is
procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
O : Object) is
begin
String'Write (S, "");
String'Write (S, Integer'Image (O.V));
String'Write (S, "");
String'Write (S, "");
end Write;
procedure Class_Output (S : access Ada.Streams.Root_Stream_Type'Class;
O : Object'Class) is
-- Write a tag of the form "", then the object.
begin
Character'Write (S, '<');
String'Write (S, Ada.Tags.External_Tag (Tag));
Character'Write (S, '>');
Object'Output (S, O); -- Dispatching call; calls Object'Write.
end Class_Output;
function Dispatching_Input is new Ada.Tags.Generic_Dispatching_Constructor
(T => Object, Parameters => Ada.Streams.Root_Stream_Type'Class,
Constructor => Object'Input);
function Class_Input (S : access Ada.Streams.Root_Stream_Type'Class)
return Object'Class is
-- Read a tag of the form "", then dispatch to reading
-- the object.
Input : String (1..20);
Input_Len : Natural := 0;
begin
Character'Read (S, Input(1));
if Input(1) /= '<' then
raise Ada.Tags.Tag_Error;
end if;
Input_Len := 0;
for I in Input'range loop
Input_Len := I;
Character'Read (S, Input(I));
exit when Input(I) = '>';
end loop;
if Input(Input_Len) /= '>' or else -- Never found closing character
Input_Len <= 1 then -- Empty tag
raise Ada.Tags.Tag_Error;
end if;
return Dispatching_Input (Ada.Tags.Internal_Tag (Input(1..Input_Len), S);
-- Dispatches to appropriate Object'Input for the tag read.
end Class_Input;
end Class;
We now have the following output:
which is what we need to write XML.
Note that overriding the stream attributes is not necessarily appropriate
(for instance, if a distributed program needed to marshall these objects).
This proposal provides a way to provide this functionality without using
the stream attributes directly (just use the subprograms directly, and
avoid defining stream attributes).
---
This proposal can also be used in other cases where object construction of
a type determined at run-time is needed. For instance, a GUI builder might
want to create an object of a particular type based on the selection of the
user from a menu. Indeed, the Claw GUI builder does exactly this in Ada 95.
Because there is no way to write a constructor, Claw uses a giant case
statement, with the resulting maintenance problems.
A Generic_Dispatching_Constructor instance would do this job better. We assume
that each control or window registers itself with the menu manager as it
elaborates. The registeration would save the tag of the type along with its
menu selection name.
In order to do that, we'd create a Construct function in the
Root_Window_Type package:
type Construct_Params is null record; -- Probably would include data about
-- the parent window here.
function Construct (Params : access Construct_Params) return Root_Window_Type;
(and of course in all of the descendants), then
function Factory is new Ada.Tags.Generic_Dispatching_Constructor (
Root_Window_Type, Construct_Params, Construct);
function Create_Object (Item_Tag : in Ada.Tags.Tag) return Access_Any_Window is
Params : aliased Construct_Params;
begin
return new Root_Window_Type'Class'(Factory (Params));
end Create_Object;
Then the menu action routine (which handles menu selections) could simply call
Create_Object with the tag identified by the menu item selected by the user.
This structure eliminates the need for any case statements anywhere in the
program, so adding or removing a control or window doesn't require modifying
a giant case statement (which compiles slowly, as it imports the entire
universe).
Note that a GUI builder needs to stream these objects (to save them into
a GUI project file) as well as construct them from a menu, so overriding
T'Input so as to use T'Class'Input for this purpose is not an option.
!corrigendum 3.9(6)
@dinsa
@xcode<@b Ada.Tags @b
@b Tag @b;>
@dinst
@xcode< No_Tag : @b Tag;>
!corrigendum 3.9(7)
@dinsa
@xcode< @b Expanded_Name(T : Tag) @b String;
@b External_Tag(T : Tag) @b String;
@b Internal_Tag(External : String) @b Tag;>
@dinst
@xcode< @b Parent_Tag (T : Tag) @b Tag;>
!corrigendum 3.9(9)
@dinsa
@xcode<@b
... -- @ft<@i>
@b Ada.Tags;>
@dinst
No_Tag is the default initial value of type Tag.
!corrigendum 3.9(12)
@dinsa
The function Internal_Tag returns the tag that corresponds to the given
external tag, or raises Tag_Error if the given string is not the external tag
for any specific type of the partition.
The function Parent_Tag returns the tag of the parent type of the type whose
tag is T. If the type does not have a parent type (that is, it was not
declared by a derived_type_declaration), then No_Tag is returned.
!corrigendum 3.9(18)
@dinsa
@xhang<@xterm
X'Tag denotes the tag of X. The value of this attribute is of type Tag.>
@dinss
The following language-defined generic function exists:
@xcode<@b
@b T (<@>) @b;
@b Parameters (<@>) @b;
@b Constructor (Params : @b Parameters)
@b T @b;
@b Ada.Tags.Generic_Dispatching_Constructor
(The_Tag : Tag;
Params : @b Parameters) @b T'Class;
@b Preelaborate(Generic_Dispatching_Constructor);
@b Convention(Intrinsic, Generic_Dispatching_Constructor);>
Tags.Generic_Dispatching_Constructor
provides a mechanism to create an object of an appropriate type from just a tag
value. The function Constructor is expected to create the object given a
reference to an object of type Parameters.
!corrigendum 3.9(25)
@dinsa
The tag is preserved by type conversion and by parameter passing. The tag of a
value is the tag of the associated object (see 6.2).
@dinss
Tag_Error is raised by a call of Expanded_Name, External_Tag, or Parent_Tag if
any tag passed is No_Tag.
An instance of Tags.Generic_Dispatching_Constructor
raises Tag_Error if The_Tag does not
represent a concrete descendant of T or if the innermost master (see 7.6.1)
of this descendant is not also a master of the instance.
Otherwise, it dispatches to the primitive function denoted by the formal
Constructor for the type identified by The_Tag, passing Params, and
returns the result. Any exception raised by the function is propagated.
@i<@s8>
If an internal tag provided to an instance of
Tags.Generic_Dispatching_Constructor or to any subprogram declared in
package Tags identifies either a type that is not library-level and whose
tag has not been created (see 13.14), or a type that does not exist in the
partition at the time of the call, then execution is erroneous.
!corrigendum 3.9(26)
@drepl
The implementation of the functions in Ada.Tags may raise Tag_Error if no
specific type corresponding to the tag passed as a parameter exists in the
partition at the time the function is called.
@dby
The implementation of Internal_Tag and Descendant_Tag may raise Tag_Error if no
specific type corresponding to the string External passed as a parameter exists
in the partition at the time the function is called, or if there is no such
type whose innermost master is a master of the point of the function call.
@i<@s8>
Internal_Tag should return the tag of a type whose innermost master is the
master of the point of the function call.
!corrigendum 3.9(30)
@dinsa
@xindent<@s9<65 If S denotes an untagged private type whose full type is
tagged, then S'Class is also allowed before the full type definition, but only
in the private part of the package in which the type is declared (see 7.3.1).
Similarly, the Class attribute is defined for incomplete types whose full type
is tagged, but only within the library unit in which the incomplete type is
declared (see 3.10.1).>>
@dinst
@xindent<@s9<66 The capability provided by
Tags.Generic_Dispatching_Constructor is sometimes known as a
@i.>>
!corrigendum 3.9.2(1)
@drepl
The primitive subprograms of a tagged type are called @i. A dispatching operation can be called using a statically
determined @i tag, in which case the body to be executed is
determined at compile time. Alternatively, the controlling tag can be
dynamically determined, in which case the call @i to a body that is
determined at run time; such a call is termed a @i. As
explained below, the properties of the operands and the context of a particular
call on a dispatching operation determine how the controlling tag is
determined, and hence whether or not the call is a dispatching call. Run-time
polymorphism is achieved when a dispatching operation is called by a
dispatching call.
@dby
The primitive subprograms of a tagged type and the subprograms declared by
@fas are called @i. A dispatching operation can be called using a statically
determined @i tag, in which case the body to be executed is
determined at compile time. Alternatively, the controlling tag can be
dynamically determined, in which case the call @i to a body that is
determined at run time; such a call is termed a @i. As
explained below, the properties of the operands and the context of a particular
call on a dispatching operation determine how the controlling tag is
determined, and hence whether or not the call is a dispatching call. Run-time
polymorphism is achieved when a dispatching operation is called by a
dispatching call.
!corrigendum 3.9.2(2)
@drepl
A @i is a call whose @fa or @fa
denotes the declaration of a primitive subprogram of a tagged type, that is, a
dispatching operation. A @i in a call on
a dispatching operation of a tagged type T is one whose corresponding formal
parameter is of type T or is of an anonymous access type with designated type
T; the corresponding formal parameter is called
a @i. If the controlling formal parameter is an
access parameter, the controlling operand is the object designated by the
actual parameter, rather than the actual parameter itself.
If the call is to a (primitive) function with result type T, then the call has
a @i -- the context of the call can control the dispatching.
@dby
A @i is a call whose @fa or @fa
denotes the declaration of a dispatching operation. A @i
in a call on a dispatching operation of a tagged type T is one whose
corresponding formal parameter is of type T or is of an anonymous access type
with designated type T; the corresponding formal parameter is called
a @i. If the controlling formal parameter is an
access parameter, the controlling operand is the object designated by the
actual parameter, rather than the actual parameter itself.
If the call is to a (primitive) function with result type T, then the call has
a @i -- the context of the call can control the dispatching.
!corrigendum 3.9.2(22)
@drepl
@xindent<@s9<73 This subclause covers calls on primitive subprograms of
a tagged type. Rules for tagged type membership tests are described
in 4.5.2. Controlling tag determination for an @fa
is described in 5.2.>>
@dby
@xindent<@s9<73 This subclause covers calls on dispatching subprograms of
a tagged type. Rules for tagged type membership tests are described
in 4.5.2. Controlling tag determination for an @fa
is described in 5.2.>>
!corrigendum 3.9.3(3)
@drepl
A subprogram declared by an @fa (see 6.1)
is an @i. If it is a primitive subprogram of a tagged
type, then the tagged type shall be abstract.
@dby
A subprogram declared by an @fa (see 6.1) or
a @fa (see 12.6)
is an @i. If it is a primitive subprogram of a tagged type,
then the tagged type shall be abstract.
!corrigendum 3.9.3(11)
@drepl
A generic actual subprogram shall not be an abstract subprogram.
The @fa of an @fa for the Access,
Unchecked_Access, or Address attributes shall not denote an abstract
subprogram.
@dby
A generic actual subprogram shall not be an abstract subprogram unless the
generic formal subprogram is declared by a
@fa.
The @fa of an @fa for the Access,
Unchecked_Access, or Address attributes shall not denote an abstract
subprogram.
!corrigendum 12.6(02)
@drepl
@xcode<@fa@ft<@b>@fa< subprogram_specification [>@ft<@b>@fa< subprogram_default];>>
@dby
@xcode<@fa@ft<@b>@fa< subprogram_specification [>@ft<@b>@fa< subprogram_default];
formal_abstract_subprogram_declaration ::=
>@ft<@b>@fa< subprogram_specification >@ft<@b>@fa< [subprogram_default];>>
!corrigendum 12.6(04)
!comment to force a conflict with null procedures, so we can disallow them for these.
@drepl
@xcode<@fa>
@dby
@xcode<@fa>
!corrigendum 12.6(08)
@dinsa
The profiles of the formal and actual shall be mode-conformant.
@dinss
If a formal parameter of a @fa is of a
specific tagged type @i or of an anonymous access type designating a
specific tagged type @i, @i is called a @i of the
@fa. Similarly, if the result of a
@fa for a function is of a specific
tagged type @i or of an anonymous access type designating a specific tagged
type @i, @i is called a controlling type of the
@fa. A
@fa shall have exactly one controlling
type.
The actual subprogram for a @fa shall
be a dispatching operation of the controlling type or of the actual type
corresponding to the controlling type.
!corrigendum 12.6(10)
@dinsa
If a generic unit has a @fa specified by a box, and the
corresponding actual parameter is omitted, then it is equivalent to an
explicit actual parameter that is a usage name identical to the defining name
of the formal.
@dinst
The subprogram declared by a @fa with a
controlling type @i is a dispatching operation of type @i.
!corrigendum 12.6(16)
@drepl
@xindent<@s9<18 The actual subprogram cannot be abstract (see 3.9.3).>>
@dby
@xindent<@s9<18 The actual subprogram cannot be abstract unless the formal
subprogram is a @fa (see 3.9.3).>>
@xindent<@s9<19 The subprogram declared by a
@fa is an abstract subprogram. All
calls on a subprogram declared by a @fa
must be dispatching calls. See 3.9.3.>>
!ACATS test
A C-Test should be constructed to test this feature.
!appendix
From: Tucker Taft
Sent: Saturday, November 13, 2004 5:43 PM
I would recommend that we allow defaults
for formal abstract subprograms.
E.g.:
formal_abstract_subprogram_declaration ::=
with subprogram_specification is abstract [subprogram_default];
That is, you should be able to write:
with procedure Input(S : access Root_Stream_Type'Class)
return T is abstract T'Input;
or
with function Image(X : T) return String is abstract <>;
There seems no justification for having to give up on defaults
just to add the requirement that the actual be a dispatching op.
****************************************************************
From: Randy Brukardt
Sent: Saturday, November 13, 2004 10:28 PM
Because the syntax is unspeakable?
Anyway, I asked this exact question at the Madison meeting, and received the
answer that it wasn't important. I thought it was you that actually voiced
that. The minutes say:
"For the dispatching formal subprogram, is abstract replaces is Default,
meaning you can't specify a default for such a subprogram. Not a big deal."
I certainly wouldn't have left it out if we hadn't already discussed it.
****************************************************************
From: Tucker Taft
Sent: Sunday, November 13, 2004 6:33 AM
> Because the syntax is unspeakable?
I think we actually discussed "is abstract is <>;" which
I agree is unspeakable. But "is abstract <>;" doesn't
seem so bad.
> Anyway, I asked this exact question at the Madison meeting, and received the
> answer that it wasn't important. I thought it was you that actually voiced
> that. The minutes say:
>
> "For the dispatching formal subprogram, is abstract replaces is Default,
> meaning you can't specify a default for such a subprogram. Not a big deal."
I think I was reacting mostly to the "is abstract is blah;" but also,
this is one of those things that didn't really hit me until later,
after I had seen some examples. I hate when you have two features,
where you are forced into choosing one or the other, but what you
really want is both, and for some apparently arbitrary reason, you
can't use the features together. I think a lot of the little fixes
we are doing this time represent attempts to make more features work
together better, so I hate to create a new situation where we disallow
reasonable feature combination.
>
> I certainly wouldn't have left it out if we hadn't already discussed it.
I think we should reconsider, based on seeing and thinking about
more examples of use.
****************************************************************
From: Robert A. Duff
Sent: Sunday, November 13, 2004 10:14 AM
> I think we actually discussed "is abstract is <>;" which
> I agree is unspeakable. But "is abstract <>;" doesn't
> seem so bad.
An "abstract <>" is a "black box". ;-)
>... I hate when you have two features,
> where you are forced into choosing one or the other, but what you
> really want is both, and for some apparently arbitrary reason, you
> can't use the features together.
I very much agree with that sentiment.
****************************************************************
From: Christoph Grein
Sent: Tuesday, February 22, 2005 4:35 AM
Ada 2005 Amendment 1 (Draft 10)
Section 3.9.3 Abstract Types and Subprograms
In the replacement for paragraph 3, the word "declared" appears twice.
****************************************************************