Assigning ARRAY_A or ARRAY_B to Z works, because you are assigning TArray<string> constants to a TArray<string> variable. They are all the same type, so they are compatible with each other.
Assigning ARRAY_C or ARRAY_D to W does not work, because you are assigning static array constants to a dynamic array variable. They are different types that are not compatible with each other, as explained in Delphi's documentation:
Type Compatibility and Identity (Delphi)
Type Compatibility
Every type is compatible with itself. Two distinct types are compatible if they satisfy at least one of the following conditions.
- They are both real types.
- They are both integer types.
- One type is a subrange of the other.
- Both types are subranges of the same type.
- Both are set types with compatible base types.
- Both are packed-string types with the same number of characters.
- One is a string type and the other is a string, packed-string, or
Char type.
- One type is
Variant and the other is an integer, real, string, character, or Boolean type.
- Both are class, class-reference, or interface types, and one type is derived from the other.
- One type is
PAnsiChar or PWideChar and the other is a zero-based character array of the form array[0..n] of PAnsiChar or PWideChar.
- One type is
Pointer (an untyped pointer) and the other is any pointer type.
- Both types are (typed) pointers to the same type and the
{$T+} compiler directive is in effect.
- Both are procedural types with the same result type, the same number of parameters, and type-identity between parameters in corresponding positions.
Assignment Compatibility
Assignment-compatibility is not a symmetric relation. An expression of type T2 can be assigned to a variable of type T1 if the value of the expression falls in the range of T1 and at least one of the following conditions is satisfied:
- T1 and T2 are of the same type, and it is not a file type or structured type that contains a file type at any level.
- T1 and T2 are compatible ordinal types.
- T1 and T2 are both real types.
- T1 is a real type and T2 is an integer type.
- T1 is
PAnsiChar, PWideChar, PChar or any string type and the expression is a string constant.
- T1 and T2 are both string types.
- T1 is a string type and T2 is a
Char or packed-string type.
- T1 is a long string and T2 is
PAnsiChar, PWideChar or PChar.
- T1 and T2 are compatible packed-string types.
- T1 and T2 are compatible set types.
- T1 and T2 are compatible pointer types.
- T1 and T2 are both class, class-reference, or interface types and T2 is a derived from T1.
- T1 is an interface type and T2 is a class type that implements T1.
- T1 is
PAnsiChar or PWideChar and T2 is a zero-based character array of the form array[0..n] of Char (when T1 is PAnsiChar) or of WideChar (when T1 is PWideChar).
- T1 and T2 are compatible procedural types. (A function or procedure identifier is treated, in certain assignment statements, as an expression of a procedural type. See "Procedural types in statements and expression" earlier in this chapter.)
- T1 is
Variant and T2 is an integer, real, string, character, Boolean, interface type or OleVariant type.
- T1 is an
OleVariant and T2 is an integer, real, string, character, Boolean, interface, or Variant type.
- T1 is an integer, real, string, character, or Boolean type and T2 is
Variant or OleVariant.
- T1 is the
IUnknown or IDispatch interface type and T2 is Variant or OleVariant. (The variant's type code must be varEmpty, varUnknown, or varDispatch if T1 is IUnknown, and varEmpty or varDispatch if T1 is IDispatch.)
Assigning ARRAY_A or ARRAY_B to Z satisfies the "Assignment Compatibility" requirements. Assigning ARRAY_C or ARRAY_D to W does not.
To solve your problem with the static arrays, you will have to use a pointer instead (a dynamic array is already a pointer), eg:
procedure TForm1.Button1Click(Sender: TObject);
type
TTestRec = record
X: string;
Y: Integer;
end;
PTestRec = ^TTestRec;
const
ARRAY_A : TArray<string> = ['A1', 'A2', 'A3', 'A4'];
ARRAY_B : TArray<string> = ['B1', 'B2', 'B3'];
ARRAY_C : array[1..2] of TTestRec = (
(X: 'testC1'; Y:1),
(X: 'testC2'; Y:2)
);
ARRAY_D : array[1..3] of TTestRec = (
(X: 'testD1'; Y:3),
(X: 'testD2'; Y:4)
(X: 'testD3'; Y:9)
);
var
Z : TArray<string>;
W : PTestRec;
begin
Z := ARRAY_A;
Z := ARRAY_B;
W := @ARRAY_C[1];
W := @ARRAY_D[1];
end;
Note, however, that there is no way to determine from W itself whether it is pointing at an array[1..2] of TTestRec or an array[1..3] of TTestRec, which are two completely different types. So, if you need to use W to iterate the arrays, you will have to keep track of the acceptable bounds separately, eg:
{$POINTERMATH ON}
procedure TForm1.Button1Click(Sender: TObject);
type
TTestRec = record
X: string;
Y: Integer;
end;
PTestRec = ^TTestRec;
const
ARRAY_A : TArray<string> = ['A1', 'A2', 'A3', 'A4'];
ARRAY_B : TArray<string> = ['B1', 'B2', 'B3'];
ARRAY_C : array[1..2] of TTestRec = (
(X: 'testC1'; Y:1),
(X: 'testC2'; Y:2)
);
ARRAY_D : array[1..3] of TTestRec = (
(X: 'testD1'; Y:3),
(X: 'testD2'; Y:4)
(X: 'testD3'; Y:9)
);
var
Z : TArray<string>;
W : PTestRec;
W_Len, I: Integer;
begin
Z := ARRAY_A;
for I := 0 to High(Z) do begin
// use Z[I] as needed ...
end;
Z := ARRAY_B;
for I := 0 to High(Z) do begin
// use Z[I] as needed ...
end;
W := @ARRAY_C[1];
W_Len := Length(ARRAY_C);
for I := 0 to Pred(W_Len) do begin
// use W[I] as needed ...
end;
W := @ARRAY_D[1];
W_Len := Length(ARRAY_D);
for I := 0 to Pred(W_Len) do begin
// use W[I] as needed ...
end;
end;