There has been a recent request to add to for loop in the Object Pascal language the ability to add a step, that is an increment different from one. Here is an alternative implementation using a for..in loop and a custom enumerator.

There has been a recent request to add to for loop in the Object Pascal language the ability to add a step, that is an increment different from one. Here is an alternative implementation using a for..in loop and a custom enumerator.

Once I saw the request it reminded me of a demo I have in my Object Pascal Handbook (which originally came from my Delphi 2007 Handbook), The demo is available at https://github.com/MarcoDelphiBooks/ObjectPascalHandbook/ blob/master/10/NumbersEnumerator/NumbersEnumerator_MainForm.pas and shows how to build an enumerator over a range of numeric value. The only missing feature is the ability to have a Step property to skip value in the sequence, counting by 2, 3, 4 and so on. The other issue of the demo is it uses an object of a class, which implies the need of creating and freeing the object. Also the way properties are set is a bit cumbersome.

In the new version (listed below) I have moved from using classes to using records, still keeping the enumeration as a nested type, and added a static class function to initialize the data structure in a single call. The goal is to be able to use it as follows:

procedure TForm1.btnTestClick(Sender: TObject); var I: Integer; begin for I in TNumbersRange.Range (5, 13, 3) do Show (IntToStr (I)); end;

Of course, you could also define a global Range () function, rather than a class method.

Below is an image with the type definition, followed by a second one with the core implementation. They are followed by the code itself, which might not be as well formatted and readable (hence the images). Feel free to use it any way you like.

Here is the record declaration and definition in text format:

type TNumbersRange = record public type TNumbersRangeEnum = record private nPos: Integer; nStart: Integer; nEnd: Integer; nStep: Integer; public constructor Create (aRange: TNumbersRange); function MoveNext: Boolean; function GetCurrent: Integer; property Current: Integer read GetCurrent; end; private NStart: Integer; NEnd: Integer; NStep: Integer; public class function Range (aStart, aEnd, aStep: Integer): TNumbersRange; static; function GetEnumerator: TNumbersRangeEnum; end; implementation uses Math; class function TNumbersRange.Range (aStart, aEnd, aStep: Integer): TNumbersRange; begin Result.NStart := aStart; Result.NEnd := aEnd; Result.NStep := aStep; end; { TNumbersRange } function TNumbersRange.GetEnumerator: TNumbersRangeEnum; begin Result := TNumbersRangeEnum.Create (self); end; constructor TNumbersRange.TNumbersRangeEnum. Create(aRange: TNumbersRange); begin nStart := aRange.NStart; nEnd := aRange.NEnd; nStep := IfThen (aRange.NStep = 0, 1, aRange.NStep); nPos := aRange.nStart - nStep; end; function TNumbersRange.TNumbersRangeEnum. GetCurrent: Integer; begin Result := nPos; end; function TNumbersRange.TNumbersRangeEnum. MoveNext: Boolean; begin Inc (nPos, nStep); Result := nPos <= nEnd; end;