Things that make you go ‘urgh’…

What’s the flaw in this test code?

program Project1;

{$APPTYPE CONSOLE}

var
  Arr1, Arr2: array of array of Integer;
  I, J: Integer;
begin
  SetLength(Arr1, 5, 5);
  for I := 0 to 4 do
    for J := 0 to 4 do
      Arr1[I, J] := I * J;
  Arr2 := Copy(Arr1);
  for I := 0 to 4 do
    for J := 0 to 4 do
      if Arr2[I, J] <> Arr1[I, J] then
      begin
        WriteLn('Nope');
        Break;
      end;
  Write('Press ENTER to exit...');
  ReadLn;
end.

I’ve just checked, and FPC lovingly duplicates the behaviour I’m thinking of too. The flaw in question was immediately spotted by Rudy Velthuis, so credit to him.

[And no, I’m not saying avoid dynamic arrays like the plague. The fact the baby’s being kept in doesn’t mean you can’t complain about the murkiness of the water.]

Advertisements

19 thoughts on “Things that make you go ‘urgh’…

  1. You might want to mention too, that IMO, that is the correct behaviour.

    Dynarrays are single-dimensional. One can get the illusion of multi-dimensionality because the Delphi syntax lets you access them using a[5,6] syntax, and SetLength takes more than one dimension parameter, and indeed, the docs even mention multi-dimensional, but that doesn’t change anything. You don’t have a multi-dimensional dynarray, you have a dynarray than contains other dynarrays. Each of these is one-dimensional. IOW, you don’t have one array, you have a cluster of dynarrays.

    Copy() handles dynarrays. These are one-dimensional, so it only does one dimension (what else?). IOW, the behaviour is correct and actually well known.

    • Do you imply that Delphi misses “real” multidimensional dynarray (allocated as a single memory block on heap)?
      IMO the one-dimensional Copy() behavior is well known only among those who bumped into the problem.

    • You’re being ridiculous, especially in your ‘well known’ assertion (I seriously doubt even Copy as such is a well-known when it comes to dynamic arrays), but I’m not going to argue with you over semantics – the debate would be like that one in non-tech arguing whether Delphi’s programming language should legitimately be called ‘Object Pascal’.

      • No, I am not being ridiculous, I am merely disagreeing with you, and reality (e.g. the code snippet YOU posted and which I amended in the Embarcadero forums) shows me to be right.

        But hey, if you think it is a bug, and want to bug Embarcadro about it, go ahead. I’m pretty sure they will agree with me that Copy() does what it is supposed to do (simply because it does), so good luck convincing them of the opposite.

    • But what is the type or Arr1[I] ? Isn’t it “pointer to dynarray of integer” ?

      Let Copy be 1D, okay. Then Arr1 and Arr2 should be different arrays, consisting of the same pointers to the same inner 1D arrays and Arr1[I] == Arr2[I] and consequently Arr1[I][J] == Arr2[I][J]

  2. Sorry for the double comment. I guess it got posted while I was correcting the spelling. No idea how that happened. Must be that the Apple keyboard I’m using still gives me problems with [ and ] etc.

  3. I’m with you Chris. I don’t think this is “well known”, maybe because mono-dimensional dynamic arrays are probably used much more than multidimensional ones.
    And also, the documentation is blaringly silent on this behavior. (credit to DelphiBasics to mention it: http://www.delphibasics.co.uk/RTL.asp?Name=Array)
    The more visibility it gets, the less bugs we’ll have to deal with.

    IMO, I don’t see why “copy” would not behave recursively and copy each sub-array as well. It seems that it is the intuitive behavior people tend to expect in the 1st place. (either nothing at all like Arr1:=Arr2, or a full recursive copy)
    But since it’s been like that for some time, I doubt it can change for compatibility reasons (breaking code relying explicitly on this behavior).

    • Thanks for the support! On my reading, the help strongly implies the behaviour I was expecting, and therefore, implies the actual behaviour to be a bug. Specifically, the entry for Copy (http://docwiki.embarcadero.com/VCL/en/System.Copy) includes the line:

      Note: When S is a dynamic array, you can omit the Index and Count parameters and Copy copies the entire array.

      What could ‘the entire array’ mean? According to Rudy, this can’t mean more than one dimension because dynamic arrays aren’t multidimensional. And yet, the Delphi Language Guide talks of ‘multidimensional dynamic arrays’ quite clearly (http://docwiki.embarcadero.com/RADStudio/en/Structured_Types#Multidimensional_Dynamic_Arrays). See also the docs for SetLength (http://docwiki.embarcadero.com/VCL/en/System.SetLength).

    • @François: If the array is an array of Integers, strings, records, objects or any other type, it simply copies these elements to the new array. Why should it, all of a sudden, act differently if the elements happen to be dynarrays?

    • Should Copy also “recursively” copy any nested arrays, e.g. if these are elements of records contained in the dynarray to be copied? If you really want a deep copy, it should, shouldn’t it?

    • While the Copy behaviour above is incorreect (and actually fixed – in Xe2U4 this gives no single “Nope” to me) when we come to “well known” – i’m with Rudy.

      I believe that every person who ever declared “multidimensional” dynarray really should “well know” it.
      I believe that every person who ever read help about using SetLength over dynarrays really should “well know” it.

      Otherwise that person never reads what he writes and then should not be considered programmer (reading the code is no less important than writing it)

      • Arioch – can you please stop adding comments to very old posts of mine. I struggle to remember the context of things I wrote two weeks ago, let alone two years ago! You are of course more than welcome to comment on more recent posts however (please do!), in which case you may actually get to debate with more than your own shadow…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s