CVS difference for ai05s/ai05-0139-2.txt
--- ai05s/ai05-0139-2.txt 2011/02/08 08:21:06 1.10
+++ ai05s/ai05-0139-2.txt 2011/02/15 04:57:58 1.11
@@ -1,9 +1,10 @@
-!standard 4.1(2/2) 10-10-25 AI05-0139-2/07
+!standard 4.1(2/2) 11-02-14 AI05-0139-2/08
!standard 4.1.5(0)
!standard 4.1.6(0)
!standard 5.5(3)
!standard 5.5(9)
!standard 5.5.1(0)
+!standard 13.3.2(9)
!class Amendment 09-02-13
!status work item 09-02-13
!status received 09-01-19
@@ -41,9 +42,16 @@
!proposal
-Define a "magic" generic unit and some additional "aspects" for the
-aspect_specification, all of which are linked to some appropriate
-syntactic sugar for accessors, containers, and iterators:
+Provide a generic unit containing two iterator interfaces, and
+some additional "aspects" related to implicit dereference and indexing,
+along with some appropriate syntactic sugar for accessors, containers,
+and iterators.
+
+We also propose providing iterators for arrays, including
+multi-dimensional arrays. As part of that, we use the notion
+of canonical order for multidimensional arrays established for
+Stream attributes, but modify it to take into account convention
+Fortran, where the first, rather than the last, dimension varies fastest.
1) SUPPORT FOR ACCESSORS/REFERENCES
@@ -433,9 +441,9 @@
Implicit_Dereference This aspect is specified by a name that denotes
an access discriminant declared for the type T.
- A type with a specified Implicit_Dereference aspect is a /reference
- type/. A /reference object/ is an object of a reference type. The
- discriminant named by the Implicit_Dereference aspect is the
+ A (view of a) type with a specified Implicit_Dereference aspect is a
+ /reference type/. A /reference object/ is an object of a reference type.
+ The discriminant named by the Implicit_Dereference aspect is the
/reference discriminant/ of the reference type or reference object.
[Redundant: A generalized_reference is a name that identifies a
reference object, and denotes the object or subprogram designated by
@@ -459,11 +467,11 @@
by descendants of type T if not overridden. If a descendant type
constrains the value of the reference discriminant of T by a new
discriminant, that new discriminant is the reference discriminant of
- the descendant. If the descendant type constrains the value of the
+ the descendant. [Redundant: If the descendant type constrains the value of the
reference discriminant of T by an expression other than the name of a
new discriminant, a generalized_reference that identifies an object of
the descendant type denotes the object or subprogram designated by the
- value of this constraining expression.
+ value of this constraining expression.]
Dynamic Semantics
@@ -479,8 +487,8 @@
Example
type Ref_Element(Data : access Element) is
- new Ada.Finalization.Limited_Controlled with null record
- with Implicit_Dereference => Data;
+ new Ada.Finalization.Limited_Controlled with private
+ with Implicit_Dereference => Data;
-- This Ref_Element type is a "reference" type.
-- "Data" is its reference discriminant.
@@ -521,8 +529,8 @@
type T'Class). The aspects may not be overridden, but the functions they
denote may be.
- An /indexable type/ is a user-defined tagged type with at least one of
- the aspects Constant_Indexing or Variable_Indexing specified. An
+ An /indexable type/ is (a view of) a user-defined tagged type with at least
+ one of the aspects Constant_Indexing or Variable_Indexing specified. An
/indexable object/ is an object of an indexable type. [Redundant: A
generalized_indexing is a name that denotes the result of calling a
function named by a Contant_Indexing or Variable_Indexing aspect.]
@@ -594,12 +602,14 @@
package Ada.Iterator_Interfaces is
type Forward_Iterator is limited interface;
- function First (Object : Forward_Iterator) return Cursor;
- function Next (Object : Forward_Iterator; Position : Cursor) return Cursor;
+ function First (Object : Forward_Iterator) return Cursor is abstract;
+ function Next (Object : Forward_Iterator; Position : Cursor) return Cursor
+ is abstract;
type Reversible_Iterator is limited interface and Forward_Iterator;
- function Last (Object : Reversible_Iterator) return Cursor;
- function Previous (Object : Reversible_Iterator; Position : Cursor) return Cursor;
+ function Last (Object : Reversible_Iterator) return Cursor is abstract;
+ function Previous (Object : Reversible_Iterator; Position : Cursor) return Cursor
+ is abstract;
end Ada.Iterator_Interfaces;
@@ -759,7 +769,9 @@
of the loop_statement is complete. Otherwise, the
sequence_of_statements is executed with the loop parameter denoting
each component of the array for the loop, using a /canonical/ order
- of components, which is last dimension varying fastest. For a
+ of components, which is last dimension varying fastest (unless the
+ array has convention Fortran, in which case it is first dimension
+ varying fastest). For a
forward array component iterator, the iteration starts with the
component whose index values are each the first in their index range,
and continues in the canonical order. For a reverse array component
@@ -794,238 +806,23 @@
constant (see above), then the indexing uses the default constant
indexing function for the type of the iteratable object for the loop;
otherwise it uses the default variable indexing function.
-
-
-!discussion [NOT FULLY UPDATED -- SEE PROPOSAL FOR SOME NEWER DISCUSSION]
-
-This is based on the earlier proposal and discussion recorded in AC-0112.TXT.
-This proposal was modified to address the comments made on that one, and has
-been simplified considerably.
-
-Note that the iterator interface can be directly applied to a container type
-(allowing it to be directly iterated) or it can be part of a separate function
-(which would allow adding additional parameters to the iterator and/or adding
-additional storage for the iterators). By using interfaces, we give maximum
-flexibility to the programmer that is using these iterators.
-
-If the creator of the iterator needs extra storage to accomplish the iteration,
-they can include it in the type of the iterator.
-
-If the creator of the iterator needs to get control when the loop is exited
-prematurely, they can define a controlled iterator type. In that case,
-(presuming that the iterator_expression was a function call) when the loop is
-exited, the Finalization routine for the iterator object will be called.
-
-We provide a form for reverse iterators. Reverse iteration makes sense for many
-kinds of containers (vectors and lists, for instance). Given that the syntax
-already exists and every Ada programmer is familiar with it, not providing it
-would quickly become one of the most common frustrations of programming in Ada.
-That seems silly.
-
-We could have simplified the proposal by requiring that all iterators support
-Last and Previous, but iterators where reverse iteration does not make sense
-would have to raise an exception when Last is called. The proposed features, in
-contrast, make a compile-time determination as to whether reverse is allowed.
-That will detect errors earlier; it generally is better to detect errors at
-compile-time if possible.
-
-
-It might appear that this proposal would require some solution to the
-instantiation for private types problem, but as the examples below show, this
-is not true.
-
-
-Note that the actual iterator type can be either limited or non-limited. The
-value of a limited iterator object is that an iterator implementation can
-assume (presuming that it only exports functions and not types) that the
-iterator object is created and destroyed with the loop. This allows safe
-cleanup operations when the loop is exited (as in the examples below).
-If that capability is not needed, an iterator implementation allow reuse of
-iterator objects (especially if no temporary storage is needed).
-
-Note that if temporary storage or loop exit actions are needed, the iterator
-object *must be* separate from the container object that it is iterating
-on. Otherwise nested loops on the same container would not work.
- for I in My_Container.Iterator loop
- for J in My_Container.Iterator loop
- ...
- end loop;
- end loop;
-The I and J loops need separate temporary storage, which must be provided by
-the iterator object (the loop can only provide the loop parameter cursor object).
-
-
-Issues:
-
-The use of a controlled type for an iterator in this proposal would require
-bounded containers to be preelaborable units, rather than pure units. We add a
-prohibition on the actual container from being controlled, so that finalization
-averse users could still use the bounded containers (but obviously not the
-iterators). This seems OK, given that the current accessor proposal (AI05-0142-4)
-has similar requirements.
-
-It would be nice for an iterator implementation to be able to prevent the
-creation of iterator objects not associated with a loop. For instance, given
-the implementation of the example below:
- My_Iter : Some_Instance.Forward_Iterator'Class := My_List.Iterator;
-would have the effect setting tampering on My_List and keeping it set until
-the object is destroyed (potentially a long time in the future). But this
-is not the natural thing to do -- it requires a lot more typing than the intended
-usage -- and no major definitional problems are encountered in this case. We
-would need a lot more mechanism to prevent the creation of objects outside of
-the loop context, so we do not try to prevent this misuse.
-
-
-Alternatives considered:
-
-One option considered was including the name of the cursor type somewhere in the
-syntax. Something like:
-
- defining_identifier : subtype_mark in [reverse] iterator_expression
-
-That was not done mainly because differs from the existing syntax for no clear
-benefit. It would make the type of the identifier clearer, but it also would
-mean that switching from a discrete iterator to a container one would require
-some syntax changes that don't really fit into the model. (One solution to that
-problem would be to optionally add the type name to the discrete for loop as
-well, but that seems like a bunch of additional changes for little value.)
-
-It should be noted that with this formulation, the existing discrete iterators
-could be considered just a predefined instantiation of this magic generic for
-discrete types. The analogy breaks down a bit for ranges (they don't look like a
-function call), but it isn't hard to imagine such a unification.
-
-!examples [NOT FULLY UPDATED -- SEE PROPOSAL FOR ADDITIONAL EXAMPLES]
+Modify second sentence of 13.13.2(9/2):
-This feature could easily be used in the existing Ada.Containers packages. We
-give a suggested implementation for Ada.Containers.Doubly_Linked_Lists; the
-other containers could be similar.
+ ... For composite types, the Write or Read attribute for each
+ component is called in canonical order, which is last dimension
+ varying fastest for an array {(unless the convention of the array is
+ Fortran, in which case it is first dimension varying fastest)}, and
+ positional aggregate order for a record.
-The start of the visible part of Ada.Containers.Doubly_Linked_Lists would be
-modified as follows:
+!discussion
- with Ada.Iterator_Interfaces;
- generic
- type Element_Type is private;
- with function "=" (Left, Right : Element_Type) return Boolean is <>;
- package Ada.Containers.Doubly_Linked_Lists is
- pragma Preelaborate(Doubly_Linked_Lists);
- pragma Remote_Types(Doubly_Linked_Lists);
-
- package Cursors is
- type Cursor is private;
- pragma Preelaborable_Initialization(Cursor);
-
- No_Element : constant Cursor;
- private
- ... -- not specified by the language
- end Cursors;
- subtype Cursor is Cursors.Cursor;
- No_Element : Cursor renames Cursors.No_Element;
-
- package Iterators is new
- Ada.Iterator_Interfaces (Cursors, No_Element);
-
- type List is new Iterators with private;
- pragma Preelaborable_Initialization(List);
-
- Empty_List : constant List;
-
- ...
-
-Note that the changes here are the addition of the nested package Cursors,
-the addition of the instantiation, and the subtype and renames to eliminate the
-effect of the nested package. The majority of the package is unchanged.
-
-After the existing procedure Reverse_Iterate, we would add a new function:
-
- function Iterate (Container : in List) return List_Iterators.Reversible_Iterator'Class;
-
-This would be described as
-
- Iterate returns an object that can be used in a loop_statement to loop
- with a loop parameter designating each node in Container, starting with the
- first node and moving the cursor as per the Next function if the reserved word
- *reverse* is not used in the user_loop_parameter_statement, and starting
- with the last node and moving the cursor as per the Previous function otherwise.
- Program_Error is propagated if any operation (in particular, the sequence_of_statements
- of the loop_statement whose iterator_expression denotes this object) tampers with
- the cursors of Container while the returned object exists.
-
-This could be implemented by defining a controlled type in the private part of
-Ada.Containers.Doubly_Linked_Lists:
-
- type Our_List_Iterator is new Ada.Controlled.Limited_Controlled and
- List_Iterators.Reversible_Iterator with record
- Our_List : access List;
- end record;
- function First (Object : Our_List_Iterator) return Cursor;
- function Next (Object : Our_List_Iterator; Position : Cursor) return Cursor;
- function Last (Object : Our_List_Iterator) return Cursor;
- function Previous (Object : Our_List_Iterator; Position : Cursor) return Cursor;
- procedure Finalize (Object : in out Our_List_Iterator);
-
-The implementation of these operations would be something like:
- function Iterate (Container : in List) return List_Iterators.Reversible_Iterator'Class is
- begin
- return Iter:Our_List_Iterator do
- Iter.Our_List := Container'Unchecked_Access;
- -- This is safe unless someone does an Unchecked_Deallocation on
- -- the container in the loop; we don't try to protect against that
- -- in other cases for Ada.Containers, so we won't here, either.
- -- Set a tampering context for Iter.Our_List.all.
- end return;
- end Iterate;
-
- function First (Object : Our_List_Iterator) return Cursor is
- begin
- return Object.Our_List.First;
- end First;
-
- function Next (Object : Our_List_Iterator; Position : Cursor) return Cursor is
- begin
- return Next (Position);
- end Next;
-
- -- Similar implementations for Last and Previous.
-
- procedure Finalize (Object : in out Our_List_Iterator) is
- begin
- -- Clear the tampering context for Object.Our_List.
- end Finalize;
-
-Note that we didn't add these interfaces to the actual container types. That was
-because we wanted these iterators to be a tampering context (thus ensuring that
-they terminate and do not lead to erroneous execution). Users would be very
-surprised if a "safe" construct like a for loop caused erroneous execution
-(which will happen if the node designated by the loop parameter is deleted).
-
-The function Iterate would normally be used directly in a loop:
-
- for C in My_List.Iterate loop
- ... Element (C) ...
- end loop;
-
-
-We could also define a partial list iterator:
-
- function Partial_Iterate (Container : in List;
- Start : in Cursor;
- Finish : in Cursor := No_Element)
- return List_Iterators.Reversible_Iterator'Class;
-
-where Start and Finish (if not No_Element) would have to be cursors for
-Container. In this case, the iteration would run from Start to Finish (or
-No_Element, if Finish is not on the list after/before Start) forward or in
-reverse. (This would also be a tampering context as above.)
-
-We would use Partial_Iterator directly in a loop:
+(See proposal.)
- for C in Partial_Iterate (My_List, Start, Finish) loop
- ... Element (C) ...
- end loop;
+!examples
+See AI05-0212-1 for examples of these features being used in the predefined
+containers packages.
!ACATS test
Questions? Ask the ACAA Technical Agent