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.