Enumerating enum types in Delphi AI answer

Regarding my previous post on Enumerating enum types in Delphi I asked claude.ai:

Question:

I need a way to iterate over all values of an enum type in Delphi. Something like:

var
  e: SomeEnumType;
for e in SomeEnum do begin
  doSomethingWith(e);
end;

But that doesn’t compile. I’d like to avoid programming a for-loop from Low() to High().

Answer:

Unfortunately, Delphi doesn’t have direct for-in syntax for enums. However, you can create a generic helper that enables this:

type
  TEnumHelper<T> = record
  private
    type
      TEnumIterator = record
      private
        FCurrent: Integer;
        FHigh: Integer;
      public
        function MoveNext: Boolean;
        property Current: T read GetCurrent;
        function GetCurrent: T;
      end;
  public
    function GetEnumerator: TEnumIterator;
  end;

implementation

function TEnumHelper<T>.GetEnumerator: TEnumIterator;
begin
  Result.FCurrent := Integer(Low(T)) - 1;
  Result.FHigh := Integer(High(T));
end;

function TEnumHelper<T>.TEnumIterator.MoveNext: Boolean;
begin
  Inc(FCurrent);
  Result := FCurrent <= FHigh;
end;

function TEnumHelper<T>.TEnumIterator.GetCurrent: T;
begin
  Result := T(FCurrent);
end;

Then you can iterate like this:

var
  e: TSomeEnumType;
  helper: TEnumHelper<TSomeEnumType>;
begin
  for e in helper do
    DoSomethingWith(e);
end;

Alternatively, if you’re working with Delphi XE7 or newer, you can write a class helper directly for your enum type, but that only works for concrete types, not generically.
If that seems too cumbersome, the classic variant is still the most compact solution:

for e := Low(TSomeEnumType) to High(TSomeEnumType) do
  DoSomethingWith(e);

While not quite as elegant as for-in, this is perfectly idiomatic for Delphi.

So, the class helper was mentioned (the enum helper generic is also an interesting idea, I have not tried it yet).

(Edit: I just tried it with Delphi 12, but the code doesn’t compile. First, the Property Current must be declared after the getter function GetCurrent. And second: This the GetEnumerator function doesn’t compile either:

function TEnumHelper<T>.GetEnumerator: TEnumIterator;
begin
  Result.FCurrent := Integer(Low(T)) - 1;
  Result.FHigh := Integer(High(T));
end;

Error: “Incompatible types” for both lines.)

So I asked it:

What would a class helper for the enum type look like?

Answer:

A class helper for a concrete enum type would look like this:

type
  TSomeEnumType = (etValue1, etValue2, etValue3, etValue4);
  
  TSomeEnumTypeHelper = class helper for TSomeEnumType
  private
    type
      TEnumIterator = record
      private
        FCurrent: Integer;
        FHigh: Integer;
      public
        function MoveNext: Boolean;
        property Current: TSomeEnumType read GetCurrent;
        function GetCurrent: TSomeEnumType;
      end;
  public
    function GetEnumerator: TEnumIterator;
  end;

implementation

function TSomeEnumTypeHelper.GetEnumerator: TEnumIterator;
begin
  Result.FCurrent := Ord(Low(TSomeEnumType)) - 1;
  Result.FHigh := Ord(High(TSomeEnumType));
end;

function TSomeEnumTypeHelper.TEnumIterator.MoveNext: Boolean;
begin
  Inc(FCurrent);
  Result := FCurrent <= FHigh;
end;

function TSomeEnumTypeHelper.TEnumIterator.GetCurrent: TSomeEnumType;
begin
  Result := TSomeEnumType(FCurrent);
end;

So not quite as elegant. So I asked explicitly for a set based solution and got this:

type
  TSomeEnumType = (etValue1, etValue2, etValue3, etValue4);
  TSomeEnumSet = set of TSomeEnumType;

const
  AllSomeEnumValues: TSomeEnumSet = [Low(TSomeEnumType)..High(TSomeEnumType)];

var
  e: TSomeEnumType;
begin
  for e in AllSomeEnumValues do
    DoSomethingWith(e);
end;

Not too bad actually. And since I didn’t mention that I wanted methods for the set members anyway, there was no need for a record helper.

The original conversation was in German, I had it translate it to English for this blog post. Also note that I was using the free version, so this is not the most advanced model available.

And just in case you followed the link to the conversation above and wondered why claude was addressing me as “Eure Hoheit” (“Your Grace”): I was so annoyed that it used the informal form of address (German “Du”, duzen) I added to my preferences:

Immer das förmliche Sie als Anrede benutzen, niemals Du.

And also had it address me as “Eure Hoheit”, just for kicks.