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?
Because an array contains order information and a set does not.
Explanation with the use of documentation:
The internal data format of a static or dynamic array:
is stored as a contiguous sequence of elements of the component type of the array. The components with the lowest indexes are stored at the lowest memory addresses.
Walking over these indices with a for in
loop is done in incremental order:
The array is traversed in increasing order, starting at the lowest array bound and ending at the array size minus one.
On the other side, the internal data format of a set:
is a bit array where each bit indicates whether an element is in the set or not.
Thus all these "indiced bits" are stored in one and the same "value". That is why a set can be typecasted to an Integer type, and why the order in which the bits are added is lost: [enum3, enum1] = [enum1, enum3]
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With