Re: Why is dynamic array length required here?

2018-10-21 Thread Samir via Digitalmars-d-learn
Stanislav, Ali, Mike -- Thank you all for your thoughtful and 
helpful replies to my queries.  Apologies that it has taken this 
long to reply to you.  I still haven't been able to find time to 
go through all of the code examples provided but hope to do so 
later this week.  If I have additional questions, I know where to 
go!


Thanks again!


Re: Why is dynamic array length required here?

2018-10-18 Thread Mike Parker via Digitalmars-d-learn

On Friday, 19 October 2018 at 02:04:37 UTC, Samir wrote:


I would have thought that since this is a dynamic array, I 
don't need to pre-assign its length.


Thanks



Just to expand on the previous answers, a dynamic array 
declaration with no initializer is an empty array:


int[] arr;
assert(arr.length == 0);

No memory has been allocated to store any elements. Appending 
elements will allocate memory. In fact, the runtime will allocate 
more than needed so that it doesn't have to allocate on each 
append.


arr ~= 1;
assert(arr.length == 1);
writeln(arr.capacity);

When the capacity is 0, the next append will trigger another 
allocation. The reserve function can be used to allocate enough 
memory for a number of elements, but the array will still be 
empty:


int[] arr;
arr.reserve(100);
assert(arr.length == 0);
writeln(arr.capacity);

Now 100+ elements can be appended without triggering an 
allocation.


Setting the length directly as Ali's example does means that not 
only is the required memory allocated, but also that the array is 
not empty.


int[] arr;
arr.length = 100;
assert(arr.length == 100);
writeln(arr.capacity);

And now the array can elements can be written to directly via the 
index operator, and a pointer to each element can be referenced 
as it is in the call to readf.


Note that it's still possible to write elements directly to a 
dynamic array without the append operator after memory has been 
reserved, but it completely bypasses the runtime.


void main() {
int[] myArray;

myArray.reserve(10);
foreach(i; 0 .. 10) {
*(myArray.ptr + i) = i;
}

assert(myArray == []);
assert(myArray.length == 0);

foreach(i; 0 .. 10) {
writeln(*(myArray.ptr + i));
}
}

This is essentially treating myArray.ptr as a C array, with no 
bounds checking and no automatic memory management. Here be 
dragons.


Re: Why is dynamic array length required here?

2018-10-18 Thread Ali Çehreli via Digitalmars-d-learn

On 10/18/2018 07:04 PM, Samir wrote:

>  myArray.length = noValues; // I get a run-time error if I comment
> this out

It's because the expression that reads the elements below is readf, 
which reads on top of an existing element.


>  while (i < noValues) {
>  write("enter value #", i+1, " ");
>  readf(" %s", [i]);

Aside: It may be possible to read like the following without taking the 
address, as readf has been improved to take references since that code 
was written:


 readf(" %s", myArray[i]);  // (not tested)

So, the answer to your question is, we need to set the length of the 
array so that there are elements to read on top of. If D had function 
templates like getResponse() that I use in the Templates chapter,


  http://ddili.org/ders/d.en/templates.html

then the best thing to do would be to append the elements directly to 
the array:


// No need to set .length beforehand
myArray ~= getResponse!int(/* ... */);

Ali



Re: Why is dynamic array length required here?

2018-10-18 Thread Stanislav Blinov via Digitalmars-d-learn

On Friday, 19 October 2018 at 02:04:37 UTC, Samir wrote:
I am working my way through the exercises in the "Programming 
in D" tutorial (http://ddili.org/ders/d.en/arrays.html).  Why 
is the line assigning the length of the dynamic array required?


[...]



Without the line:

myArray.length = noValues;

I get the run-time error...


I would have thought that since this is a dynamic array, I 
don't need to pre-assign its length.


Even though the array is dynamic, it doesn't have infinite 
storage. So you either:


- preallocate required storage, like in that example code (note 
that it's not the same as making a fixed-size ('static') array: 
in your case you only learn what the required length is at 
run-time, as opposed to static arrays where you must know it at 
compile time)


- don't preallocate, but instead append new elements like this:

myArray ~= newValue;

The latter isn't a universally "good" advice: it may cause 
reallocation every time you do that. That's why it's almost 
always best to preallocate in advance if you do know the length, 
or use something like std.array.appender that attempts to reduce 
memory reallocation. I'm not familiar with Ali's tutorials, maybe 
he talks about the appender in some future examples.