Delphi pitfalls: Enumerated types and for loops

Not all for loops are created equal.

Consider
for x in [value1, value2, value3]

You would expect to see x vary in the order of the values in the list.

However – if x and the values are of an enumerated type, looping the “list”
does NOT loop in the apparent order of the constant, but in the order of the enumerated type declaration, such as it would for any set.

An example:

program EnumArrayvsEnumSet;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TEnum = (plough, foo, bar, wtf);
procedure Output(const aEnum: TEnum);
begin
case aEnum of
wtf: Writeln('wtf');
plough: Writeln('plough');
bar: Writeln('bar');
foo: Writeln('foo');
else Writeln('Missed one!');
end;
end;
procedure TestEnumSet;
var
enum: TEnum;
begin
for enum in [wtf, plough, bar, foo]
do Output(enum);
end;
procedure TestEnumArray;
var
enum: TEnum;
enumArray: TArray<TEnum>;
begin
enumArray := [wtf, plough, bar, foo];
for enum in enumArray
do Output(enum);
end;
begin
try
try
Writeln('Declared: TEnum = (plough, foo, bar, wtf)');
Writeln('Test order: [wtf, plough, bar, foo]');
Writeln;
Writeln('Looping an Enum Set');
TestEnumSet;
Writeln;
Writeln('Looping an Enum Array');
TestEnumArray;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
Writeln;
Write('Press Enter:');
Readln;
end;
end.

The above code yields

Declared: TEnum = (plough, foo, bar, wtf)
Test order: [wtf, plough, bar, foo]

Looping an Enum Set
plough
foo
bar
wtf

Looping an Enum Array
wtf
plough
bar
foo

Press Enter:

This can be easy to miss, so if loop order is important – make sure you code your enums into an actual array and do not leave them as a set.

Leave a Reply