pyscripter 689 Posted December 6, 2021 I am sure this is well known but I recently discovered a new way to copy dynamic arrays: var A, B : TArray<Integer>; ... B = A; SetLength(B, Length(B)); ... Test procedure: procedure Test(); var A, B : TArray<Integer>; begin A := [1 , 2, 3]; B := A; SetLength(B, Length(B)); B[1] := 12; Assert(A[1] = 2); Assert(B[1] = 12); end; Of course Copy is simpler, but in my use case I did not want to create a copy unless it was necessary e.g. In one part of the code // create A SetLength(A, L); ... In another part of the code B = A // do stuff with B or store it as an object field If A is not recreated you save the copying operation. Not a big deal... 1 Share this post Link to post
corneliusdavid 214 Posted December 6, 2021 47 minutes ago, pyscripter said: SetLength(B, Length(B)); Wouldn't you want to set B's length to Length(A)? Share this post Link to post
Anders Melander 1782 Posted December 6, 2021 5 minutes ago, corneliusdavid said: Wouldn't you want to set B's length to Length(A)? B := A makes them the same array. SetLength just makes B unique (and contains an implicit copy). I don't get what advantage assignment followed by SetLength gives you over a simple Copy. With Copy the intent is explicit. 1 Share this post Link to post
David Heffernan 2345 Posted December 6, 2021 14 minutes ago, corneliusdavid said: Wouldn't you want to set B's length to Length(A)? Why would that be different? 1 Share this post Link to post
pyscripter 689 Posted December 6, 2021 1 minute ago, Anders Melander said: I don't get what advantage assignment followed by SetLength gives you over a simple Copy. In the use case I described you avoid copying until (if) it is needed. 2 minutes ago, Anders Melander said: With Copy the intent is explicit. Agree. Share this post Link to post
corneliusdavid 214 Posted December 6, 2021 Just now, David Heffernan said: Why would that be different? That's just as good a question. So either the assignment statement simply copies all elements it knows about in array A without setting the length of B (which seems like an incomplete copy) or setting the length is not needed. Share this post Link to post
Uwe Raabe 2057 Posted December 6, 2021 The assignment just sets the pointer and increments the reference count. Share this post Link to post
Anders Melander 1782 Posted December 6, 2021 Just now, pyscripter said: In the use case I described you avoid copying until (if) it is needed. I still don't get it. Just start with the assignment and use B:= Copy(B) when you need it to be unique.... Ah, I think I get it now. You don't want to keep track of the arrays reference count. So it's like UniqueString for dynamic arrays? Does nothing if the reference count is already 1, otherwise makes a unique copy. Right? Share this post Link to post
Anders Melander 1782 Posted December 6, 2021 5 minutes ago, corneliusdavid said: So either the assignment statement simply copies all elements it knows about in array A without setting the length of B (which seems like an incomplete copy) or setting the length is not needed. Read what I wrote again. Share this post Link to post
corneliusdavid 214 Posted December 6, 2021 I just tested this in Delphi 11: program ArrayCopy; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; procedure ShowArray(AnArray: TArray<Integer>); begin Writeln('Length: ' + Length(AnArray).ToString); for var i := 0 to Length(AnArray) - 1 do Writeln('[' + i.ToString + '] = ' + AnArray[i].ToString); end; begin var a, b: TArray<Integer>; a := [1, 2, 3]; ShowArray(a); b := a; b[1] := 12; ShowArray(b); Readln; end. And the output shows SetLength() is not necessary: Share this post Link to post
pyscripter 689 Posted December 6, 2021 (edited) 9 minutes ago, Anders Melander said: Just start with the assignment and use B:= Copy(B) when you need it to be unique.... Ah, I think I get it now. You don't want to keep track of the arrays reference count. So it's like UniqueString for dynamic arrays? Does nothing if the reference count is already 1, otherwise makes a unique copy. Right? B=A does not cost much B = Copy(A, 0) moves memory and has a cost. In my use case A may be recreated (maybe not). If it is not recreated then I save the moving of memory. If it is recreated B becomes a unique copy after SetLength(A,...) Edited December 6, 2021 by pyscripter 2 Share this post Link to post
corneliusdavid 214 Posted December 6, 2021 1 minute ago, pyscripter said: If it is recreated B becomes unique after SetLength(A,...) Isn't B already unique? See the output of my test program--those are distinct arrays. Share this post Link to post
pyscripter 689 Posted December 6, 2021 1 minute ago, corneliusdavid said: just tested this in Delphi 11: Try to output a again at the end of your routine. Share this post Link to post
corneliusdavid 214 Posted December 6, 2021 Ah! Yes, I see it now! Calling SetLength() is necessary to make it unique! Share this post Link to post
Anders Melander 1782 Posted December 6, 2021 4 minutes ago, pyscripter said: B=A does not cost much B = Copy(A, 0) moves memory and has a cost. In my use case A may be recreated (maybe not). If it is not recreated then I save the moving of memory. If it is recreated B becomes a unique copy after SetLength(A,...) A simple "yes" would have been enough 🙂 1 Share this post Link to post
Rollo62 536 Posted December 7, 2021 (edited) I am just considering what could be the use cases. How would it behave if you put B into a const parameter, passing it into a procedure. Is the SetLength( AParamOfB, SizeOf( AParamOfB ); behaviour then still be maintained ? This could maybe make sense, to have several different functions, while some need a unique copy, some don't. Edited December 7, 2021 by Rollo62 Share this post Link to post
Attila Kovacs 629 Posted December 7, 2021 I'm not sure that is well known or frequently needed, I think I saw it first here (maybe, dunno): https://stackoverflow.com/questions/19466038/finding-common-elements-in-two-arrays/19524788#19524788 Share this post Link to post
David Heffernan 2345 Posted December 7, 2021 What would be nice would be if Emba could add a MakeUnique(arr) so that you could write code like with with clear intent 1 Share this post Link to post
Anders Melander 1782 Posted December 7, 2021 There's DynArrayUnique but it's undocumented and not really fit for direct use: procedure DynArrayUnique(var A: Pointer; typeInfo: Pointer); begin if (A <> nil) and (PDynArrayRec(PByte(A) - SizeOf(TDynArrayRec))^.RefCnt > 1) then DynArrayCopy(A, A, typeInfo); end; 1 Share this post Link to post
Anders Melander 1782 Posted December 7, 2021 2 hours ago, Attila Kovacs said: I'm not sure that is well known It's in the documentation... So probably not 🙂 Share this post Link to post