Search code examples
delphidelphi-xe8

Why do literals of the form [...] have meaning that appears to depend upon context?


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?


Solution

  • 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.