arraysloopsfor-loopdelphireference-counting

TArray Result not always initially () within for loop?


Result in Test is NOT always initially ()

I have found Do I need to setLength a dynamic array on initialization?, however I do not fully understand that answer

More importantly, what is the best approach to "break" the Result/A connection (I need the loop)? Perhaps some way to force the compiler to "properly" initialize? Manually adding Result := nil as first line in Test?

function Test(var A: TArray<Integer>): TArray<Integer>;
begin
  SetLength(Result, 3); // Breakpoint here
  Result[0] := 2;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  A: TArray<Integer>; // Does not help whether A is local or global
  I: Integer;
begin
  for I := 1 to 3 do
    A := Test(A); // At Test breakpoint:
                  // * FIRST loop: Result is ()
                  // * NEXT loops: Result is (2, 0, 0)
                  //               modifying Result changes A (immediately)
  A := Test(A);   // Result is again ()
end;

Solution

  • While I hesitate to call this For compiler optimization a bug, this is certainly unhelpful if modifying array elements directly:

    function Test(var A: TArray<Integer>): TArray<Integer>;
    begin
      if Length(Result) > 0 then // Breakpoint
        Result[1] := 66; // A modified!
      SetLength(Result, 3);
      Result[0] := Result[0] + 1; // A not modified
      Exit;
      A[9] := 666; // Force linker not to eliminate A
    end;
    

    After investigation, I conclude that functions that affect the entire array (e.g. SetLength, Copy or some other function that returns TArray<Integer>) will -- unsurprisingly -- "break" the Result/A identicality created by the For loop.

    It would appear that the safest approach is (as per the answer linked to in the original post) to Result := nil; as first line in Test.

    If there are no further suggestions, I will eventually accept this as the answer.

    NOTE: As an added bonus, starting with Result := nil prevents the array from being copied by SetLength -- obvious, but for e.g. an array of 100000 being looped 100000 times this little modification effectuates a ~40% faster execution time