Consider the following program:
{$APPTYPE CONSOLE}
type
TMyEnum = (enum1, enum2, enum3);
var
Arr: TArray<TMyEnum>;
Enum: TMyEnum;
begin
Arr := [enum3, enum1]; // <-- this is an array
for Enum in Arr do
Writeln(ord(Enum));
Writeln('---');
for Enum in [enum3, enum1] do // <-- this looks very much like the array above
Writeln(ord(Enum));
Writeln('---');
Readln;
end.
The output is:
2 0 --- 0 2 ---
Why do the two loops produce different output?
for Enum in Arr do
Writeln(ord(Enum));
Here, Arr
is an array, and so the items of the array are output in order. The documentation says:
The array is traversed in increasing order.
Hence 2
is output before 0
.
for Enum in [enum3, enum1] do
Writeln(ord(Enum));
Here, [enum3, enum1]
is a set and the enumerator for a set happens to enumerate in order of increasing ordinal value. So the output has 0
first.
I don't think that is stated anywhere in the documentation that sets are enumerated in that order, but empirically that appears to be the case. However, since sets are an unordered type one should not be relying on their enumeration order anyway.
So the question then becomes understanding how [...]
can be a set or an array at different points in the code. This all stems from the new XE7 dynamic array syntax which introduces (another) syntactical ambiguity. When we write
Arr := [enum3, enum1];
then [enum3, enum1]
is an array. The compiler knows that Arr
is an array and that information defines the type of the literal.
But when we write
for Enum in [enum3, enum1] do
then [enum3, enum1]
is a set. Here the literal could in principle be either array or set. In such situations, I believe that the compiler will always prefer sets.
Again, I can't find any documentation that states that this is so, but empirically this is the case. Presumably since set enumerators pre-date the new dynamic array syntax they take precedence when there is ambiguity.
The meaning of a literal of the form [...]
depends on its context.