Skip to content

[feature] Use Constant_Reference instead of Element in Iterable #191

@clairedross

Description

@clairedross

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.

Metadata

Metadata

Assignees

Labels

STAT::designThere is a team allocated to work on the refinement of the RFCenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions