[fpc-devel] for-in-index loop

Sven Barth pascaldragon at googlemail.com
Fri Jan 25 19:17:53 CET 2013


On 25.01.2013 17:18, Alexander Klenin wrote:
> With this in mind, consider a user who wants to iterate over the
> following array:
>
> var
>    a: array [1..5] of Integer = (1, 2, 9, 4, 5);
>
> In my proposal, he should write:
> var
>    v, i: Integer;
> begin
>    for a in a index i do
>      Writeln(i, ' ', v);
> end.
>
> In your proposal, he should write (suppose GIter is a unit
> implementing the generic array iterator):
> uses
>    GIter;
> type
>    TArrayIntIterator = specialize TArrayIterator<Integer>;
>    i: TArrayIntIterator.TElem;
> begin
>    for i in TArrayIntIterator.Create(a) do
>      Writeln(i.Index + Low(a), ' ', i.Value);
> end.

One could also do an alternative (though currently not with arrays, but 
with type helper support even that would be possible...):

=== code begin ===

type
   // let's assume we extend fgl.TFPGMap a bit
   TFPGMap<Key, Data> = class
   public type
     TIteratorProc = procedure(const aKey: Key; const aValue: Data);
   public
     procedure Iterate(aProc: TIteratorProc);
   end;

// skipping the implementation of TFPGMap.Iterate...

// somewhere else

   procedure Iterator(const aKey: String; const aValue: TObject);
   begin
     Writeln(aKey, ' => ', aValue.ClassName);
   end;

type
   TFPGMapStringTObject = specialize TFPGMap<String, TObject>;
var
   map: TFPGMapStringTObject;
begin
   // set up map

   map.Iterate(@Iterator);
end;

=== code end ===

With support for anonymous functions (and changing TIteratorProc to 
"reference to procedure(...)") it even becomes:

=== code begin ===

begin
   map.Iterate(procedure(const aKey: String; const aValue: TObject)
     begin
       Writeln(aKey, ' => ', aValue.ClassName);
     end;
   );

end;

=== code end ===

And for a given array type and type helper support you can do the following:

=== code begin ===

var
   t: TLongIntArray; // there exists a helper for this type that 
implements a Iterate function
begin
   // set up t
   t.Iterate(@Iterator);
   // or
   t.Iterate(procedure(const aIndex, aData: LongInt)
     begin
       Writeln(aIndex, ' => ', aData);
     end;
   );
end;

=== code end ===

In all cases the iterate function would iterate the "container" type 
with a fitting algorithm and just call the given function with the 
necessary data. This is in my opinion a rather flexible way of dealing 
with iteration (by adding additional arguments you could for example 
influence the iteration direction).

Regards,
Sven



More information about the fpc-devel mailing list