www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Capacity is "first-come first served" for multiple slices to all

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
(Thanks to Luís Marques for waking me up.)

Although it makes sense now, somehow some parts of this story is news to 
me after all these years. :-/

When there are multiple slices to all elements of an array, they all 
start with same capacity until an element is added to one of them. After 
that, all the other slices get zero capacity:

import std.stdio;

void report(alias arr)()
{
     writefln("%s - capacity: %s, %s",
              arr.stringof, arr.capacity, arr);
}

void main()
{
     // Multiple slices to all elements
     auto a0 = [ 1, 2, 3, 4 ];
     auto a1 = a0;
     auto a2 = a0;

     void reportAll()
     {
         report!a0;
         report!a1;
         report!a2;
     }

     reportAll();
     a1 ~= 42;    // <-- After this, only a1 will have capacity
     reportAll();
}

The output shows that a0 an a2 lose capacity:

a0 - capacity: 7, [1, 2, 3, 4]
a1 - capacity: 7, [1, 2, 3, 4]
a2 - capacity: 7, [1, 2, 3, 4]
a0 - capacity: 0, [1, 2, 3, 4]
a1 - capacity: 7, [1, 2, 3, 4, 42]
a2 - capacity: 0, [1, 2, 3, 4]

Although I've known about the "perceived non-determinism"[1] about all 
this, what is still especially surprising to me is that passing a slice 
to a function can make the original slice lose capacity:

import std.stdio;

void foo(int[] arr)
{
     arr ~= 42;
}

void main()
{
     auto arr = [ 1, 2 ];
     writefln("Before calling foo(): %s", arr.capacity);
     foo(arr);
     writefln("After calling foo() : %s", arr.capacity);
}

The output shows that the original variable in main() loses capacity:

Before calling foo(): 3
After calling foo() : 0

Ali

[1] http://dlang.org/d-array-article.html
Apr 30 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, April 30, 2015 11:59:00 Ali Çehreli via Digitalmars-d-learn wrote:
 (Thanks to Luís Marques for waking me up.)

 Although it makes sense now, somehow some parts of this story is news to
 me after all these years. :-/

 When there are multiple slices to all elements of an array, they all
 start with same capacity until an element is added to one of them. After
 that, all the other slices get zero capacity:
LOL. This is the sort of thing that's pretty straightforward when you think through how arrays work, but it seems like so few people understand it. You'd _think_ that array slicing its associated semantics wouldn't be all that hard to understand, but it seems like it trips most of us up from time to time, and pretty much everyone has trouble with them initially. I expect that part of the problem is simply the fact that it's all hidden behind T[] rather than actually seeing something like struct Array(T) { size_t length; T* ptr; } when you're coding, since that alone makes a lot of the basic array semantics a lot more clear, and even if the capacity situation isn't clear at that point, at least it's clear that it's not actually part of the array itself, which makes some of semantics that one might expect with something like a vector clearly not work. I'm definitely going to have to cover some of the array basics in my talk on ranges at dconf, simply because of how much they affect ranges and how often they're misunderstand. And I _still_ occasionally end up "Aha!" moments occasionally when dealing with this stuff... - Jonathan M Davis
Apr 30 2015