Recent

Author Topic: Best practice for dynamic array creation  (Read 838 times)

MountainQ

  • Jr. Member
  • **
  • Posts: 65
Best practice for dynamic array creation
« on: October 27, 2020, 11:13:17 am »
Hi everyone; I use dynamic arrays a lot; their creation is often met with compiler hints that I would like to address.

Reading this post
https://stackoverflow.com/questions/5314918/do-i-need-to-setlength-a-dynamic-array-on-initialization/5315254#5315254
I finally understood why the result of a function has to be treated explicitly.

However, why are local variable an issue? Something simple as the following throws a hint.
Code: Pascal  [Select][+][-]
  1. type:
  2.   TIA: array of integer;
  3. var
  4.    ia: TIA;
  5. begin
  6.   SetLength(ia, 10);
  7. end;
  8.  
In the docs
https://www.freepascal.org/docs-html/rtl/system/setlength.html
it is stated that new elements are initialized; here I cannot see how I would end up in an undefined state.

What is the best solution (to a luckily minor problem) in case
a) I want to ensure that I have a correctly initialized array; is there something shorter than inserting
Code: Pascal  [Select][+][-]
  1. ia := Default(TIA)
b) I do not care about the content of the array?


Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Best practice for dynamic array creation
« Reply #1 on: October 27, 2020, 11:24:19 am »
When you call SetLength you don't need to initialize the array before hand. SetLength ensures the uniqueness of the array (lazy copy behavior), so no matter what could have been done previously to that array, as long as you don't care what is written into the array there is no need to initialize an array before calling setlength.

If you simply want to do it to get rid of hints (I have currently no lazarus installed so I don't know when it throws them and when not), the shortest way is to assign nil:
Code: Pascal  [Select][+][-]
  1. myArray := nil;

MountainQ

  • Jr. Member
  • **
  • Posts: 65
Re: Best practice for dynamic array creation
« Reply #2 on: October 27, 2020, 11:35:04 am »
Thank you @Warfley for your quick reply.
Your answer seems to imply that lazarus an not the compiler is creating this hint; is that correct?
In that case as simple suppression of the hint seems appropriate.

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: Best practice for dynamic array creation
« Reply #3 on: October 27, 2020, 11:50:53 am »
In certain conditions (not in your example) simply only doing SetLength(DynArr, ALength) will give you unexpected results.
So the warning is not useless.

Marco can give you an example where it will fail (I always forget the when and why).

Bart

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Best practice for dynamic array creation
« Reply #4 on: October 27, 2020, 12:22:25 pm »
Your answer seems to imply that lazarus an not the compiler is creating this hint; is that correct?
No its generated by the compiler. I just mentioned lazarus as a short term for lazarus and fpc.

In certain conditions (not in your example) simply only doing SetLength(DynArr, ALength) will give you unexpected results.
There is the case where if the array previously contained data, that data will be copied. So if it contains something like managed records that do non lazy copy, this might result in massive overhead. Other than that, the only thing I can think of is that this may result in already having values in your array and not just the default. But maybe I'm missing something

MountainQ

  • Jr. Member
  • **
  • Posts: 65
Re: Best practice for dynamic array creation
« Reply #5 on: October 27, 2020, 01:36:45 pm »
Thanks you both for the comments; I am curious if anything else will come up.

My intention is to have a recommendation in these rather common situations.

I kind of hesitate to block/ignore compiler hints (even for just a single line).
There is the simple solutions of using either 'default' or 'nil' before 'setlength'.
What is a good solution in case I do not care about the content. Typically I loop through the array immediately after that.
Best to all

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Best practice for dynamic array creation
« Reply #6 on: October 27, 2020, 03:29:18 pm »
When you call SetLength you don't need to initialize the array before hand. SetLength ensures the uniqueness of the array (lazy copy behavior), so no matter what could have been done previously to that array, as long as you don't care what is written into the array there is no need to initialize an array before calling setlength.

There is an exception to this and that is the Result variable as already hinted at by MountainQ's initial post.

Take the following example:

Code: Pascal  [Select][+][-]
  1. program tarrtest;
  2.  
  3. {$modeswitch result}
  4.  
  5. type
  6.   TLongIntArray = array of LongInt;
  7.  
  8. function Test1: TLongIntArray;
  9. begin
  10.   Result := [1, 2, 3];
  11. end;
  12.  
  13. function Test2: TLongIntArray;
  14. begin
  15.   SetLength(Result, 5);
  16. end;
  17.  
  18. var
  19.   l: TLongIntArray;
  20.   i: LongInt;
  21. begin
  22.   l := Test1;
  23.   for i in l do
  24.     Write(i, ' ');
  25.   Writeln;
  26.  
  27.   l := Test2;
  28.   for i in l do
  29.     Write(i, ' ');
  30.   Writeln;
  31. end.

This will result in the following output:

Code: [Select]
1 2 3
1 2 3 0 0

Thus if you expect the elements of Result to be 0 in Test2, that assumption is incorrect.

This behaviour is intended and by design (and can also happen in Delphi). This also applies if the result type is one of the managed String types (AnsiString, UnicodeString).

So for the Result variable it's safest to set a dynamic array to Nil.

For local variables I've questioned the hint on the core mailing list in the past already, but fpk did not agree with me.

 

TinyPortal © 2005-2018