-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Summary
The Iterable aspect is a GNAT specific aspect that provides user defined iteration over containers. Currently it requires First, Next, and Has_Element functions to iterate over the cursors of the container (at least), and an Element function can be added to obtain iteration over the content of the container (for Item of C loop, instead of for Position in Container loop). I would be interesting to allow providing a Constant_Reference function returning an anonymous access-to-constant view of the element instead of the Element function.
As an example, we currently have:
type List (Capacity : Count_Type) is private
with
Iterable =>
(First => First,
Next => Next,
Has_Element => Has_Element,
Element => Element),
function Element (Container : List; Position : Cursor) return Element_Type;We could instead allow:
type List (Capacity : Count_Type) is private
with
Iterable =>
(First => First,
Next => Next,
Has_Element => Has_Element,
Constant_Reference => Constant_Reference),
function Constant_Reference (Container : List; Position : Cursor) return not null access constant Element_Type;A loop:
for E of Container loop
P (E);
end loop;Would be equivalent to:
declare
Position : Cursor := First (Container);
begin
while Has_Element (Container, Position) loop
declare
Ref : constant access constant Element_Type := Constant_Reference (Container, Position);
E : Element_Type renames Ref.all;
begin
P (E);
end;
Position := Next (Container, Position);
end loop;
end;Motivation
The use of Constant_Reference would avoid copying the element, in particular in quantified expressions where using a while loop is not an alternative (at least for spark).
Caveats and alternatives
A small caveat is that, since E is a renaming and not an object, it would not be possible to use it at certain places, for example inside Global and Depends contracts. It sound minor to me though.
As a follow-up, we could consider having a way to supply a Reference function that would allow direct mutation inside the container. It is notably more complicated to do that in a SPARK-compatible way though, because of aliasing restrictions, so it may be better to keep it as a separate RFC.