Jump to page: 1 24  
Page
Thread overview
I don't like slices in D
Oct 17, 2013
Vitali
Oct 17, 2013
David Eagen
Oct 17, 2013
Vitali
Oct 17, 2013
Jonathan M Davis
Oct 17, 2013
Vitali
Oct 17, 2013
Lionello Lunesu
Oct 18, 2013
Jesse Phillips
Oct 17, 2013
John Colvin
Oct 17, 2013
Vitali
Oct 17, 2013
Ali Çehreli
Oct 17, 2013
Adam D. Ruppe
Oct 17, 2013
David Nadlinger
Oct 17, 2013
Vitali
Oct 17, 2013
Jonathan M Davis
Oct 18, 2013
Vitali
Oct 18, 2013
Adam D. Ruppe
Oct 18, 2013
Dicebot
Oct 18, 2013
Dicebot
Oct 18, 2013
Adam D. Ruppe
Oct 18, 2013
bearophile
Oct 18, 2013
bearophile
Oct 19, 2013
Jakob Ovrum
Oct 19, 2013
Jakob Ovrum
Oct 17, 2013
qznc
Oct 17, 2013
Ali Çehreli
Oct 17, 2013
Sean Kelly
Oct 18, 2013
Ali Çehreli
Oct 17, 2013
Meta
Oct 17, 2013
Ali Çehreli
Oct 17, 2013
Meta
Oct 17, 2013
Vitali
Oct 17, 2013
Adam D. Ruppe
Oct 17, 2013
Jonathan M Davis
Oct 17, 2013
David Nadlinger
Oct 17, 2013
David Nadlinger
Oct 17, 2013
David Nadlinger
October 17, 2013
I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.

Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.

Here a little example (it fails):

  void testSlices() {
    int[] dArr = [10, 11, 12];
    int[] dSlice = dArr[0..2];
    dSlice.length++;
    assert(dArr[2]==dSlice[2]); // failure
  }
October 17, 2013
On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
> I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.
>
> Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.
>
> Here a little example (it fails):
>
>   void testSlices() {
>     int[] dArr = [10, 11, 12];
>     int[] dSlice = dArr[0..2];
>     dSlice.length++;
>     assert(dArr[2]==dSlice[2]); // failure
>   }


Change your slice to
int[] dSlice = dArr[0..$] or [0..3];

The way you are doing it only takes the first 2 elements.

Modified code:

import std.stdio : writeln;

void main()
{
  int[] dArr = [10, 11, 12];
  int[] dSlice = dArr[0..$];
  assert(dArr[2] is dSlice[2]); // passes
  dSlice.length++;
  assert(dArr[2] == dSlice[2]); // passes
}
October 17, 2013
On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
> I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.
>
> Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.
>
> Here a little example (it fails):
>
>   void testSlices() {
>     int[] dArr = [10, 11, 12];
>     int[] dSlice = dArr[0..2];
>     dSlice.length++;
>     assert(dArr[2]==dSlice[2]); // failure
>   }

What's the use case for this? I haven't found myself ever needing something like that so far, but i'd be open to seeing an example.
October 17, 2013
On Thursday, 17 October 2013 at 18:21:30 UTC, David Eagen wrote:
> On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
>> I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.
>>
>> Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.
>>
>> Here a little example (it fails):
>>
>>  void testSlices() {
>>    int[] dArr = [10, 11, 12];
>>    int[] dSlice = dArr[0..2];
>>    dSlice.length++;
>>    assert(dArr[2]==dSlice[2]); // failure
>>  }
>
>
> Change your slice to
> int[] dSlice = dArr[0..$] or [0..3];
>
> The way you are doing it only takes the first 2 elements.
>
> Modified code:
>
> import std.stdio : writeln;
>
> void main()
> {
>   int[] dArr = [10, 11, 12];
>   int[] dSlice = dArr[0..$];
>   assert(dArr[2] is dSlice[2]); // passes
>   dSlice.length++;
>   assert(dArr[2] == dSlice[2]); // passes
> }

This doesn't answer my question.

I repeat my question: "Why does a reallocation accure AFTER a resize of the length of a slice, although there is still capacity?"
October 17, 2013
On 10/17/2013 11:00 AM, Vitali wrote:

> I expected slices to be in D (http://dlang.org/arrays.html)

There is also this article:

  http://dlang.org/d-array-article.html

> like they
> are in Go (http://blog.golang.org/go-slices-usage-and-internals). But
> they are not.

Every design comes with pros and cons. Go's slices can do that because they consis of three members: pointer, length, and capacity. Apparently they also know the actual array that they provide access to.

D slices have only the first two of those members. (However, the capacity can still be obtained by the function capacity(), which is ordinarily called with the property syntax.)

> Why the array have to be reallocated after the length of a slice is
> changed?

The effect of incrementing length is adding an element to the end. Since slices don't own the underlying array elements, in order to preserve the potential element beyond their current end, the entire slice gets relocated. As described in the article above, this does not happen every time.

> It makes slices useless.

Slices have been very useful so far. Slices do have some gotchas, neither of which have been showstoppers.

> Here a little example (it fails):
>
>    void testSlices() {
>      int[] dArr = [10, 11, 12];
>      int[] dSlice = dArr[0..2];
>      dSlice.length++;

That operation has a potential of relocating the slice. You can check whether that will be the case:

    if (slice.capacity == 0) {
        /* Its elements would be relocated if one more element
         * is added to this slice. */

        // ...

    } else {
        /* This slice may have room for new elements before
         * needing to be relocated. Let's calculate how
         * many: */
        auto howManyNewElements = slice.capacity - slice.length;

        // ...
    }

>      assert(dArr[2]==dSlice[2]); // failure
>    }

Ali

October 17, 2013
On Thursday, 17 October 2013 at 18:29:47 UTC, John Colvin wrote:
> On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
>> I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.
>>
>> Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.
>>
>> Here a little example (it fails):
>>
>>  void testSlices() {
>>    int[] dArr = [10, 11, 12];
>>    int[] dSlice = dArr[0..2];
>>    dSlice.length++;
>>    assert(dArr[2]==dSlice[2]); // failure
>>  }
>
> What's the use case for this? I haven't found myself ever needing something like that so far, but i'd be open to seeing an example.

The use case is:

void appendElement(ref int[] arr, int x) {
  arr ~= x;
}

void removeElement(ref int[] arr, int index) {
  arr = arr[0..index] ~ arr[index+1..$];
}

void main() {
  int[] arr = [1, 2, 3];
  arr.reserve(7);       // Reserve capacity.
  arr.appendElement(4); // Here should be
  arr.removeElement(1); // no realocation of array,
  arr.appendElement(5); // but it is.
  assert(arr[1] == 3);
  assert(arr[2] == 4);
  assert(arr[3] == 5);
}

But maybe I don't understand what slices are for in D. Anyway in Go this works whithout reallocation.
October 17, 2013
On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
> I expected slices to be in D (http://dlang.org/arrays.html) like they are in Go (http://blog.golang.org/go-slices-usage-and-internals). But they are not.
>
> Why the array have to be reallocated after the length of a slice is changed? It makes slices useless.
>
> Here a little example (it fails):
>
>   void testSlices() {
>     int[] dArr = [10, 11, 12];
>     int[] dSlice = dArr[0..2];
>     dSlice.length++;
>     assert(dArr[2]==dSlice[2]); // failure
>   }

As David Eagen said, your problem is that in D, dArr[0..2] is not inclusive, it's exclusive, so you get dArr[0] and dArr[1]. Changing it to dSlice = dArr[0..3] will work (or better, dArr[0..$]). However, there's something else going on here that's fishy:

void testSlices()
{
	int[] dArr = [10, 11, 12];
	int[] dSlice = dArr[0..2];
	writeln(dArr.ptr, " ", dArr.capacity, " ", dArr.length);
	writeln(dSlice.ptr, " ", dSlice.capacity, " ", dSlice.length);

	dSlice.length++;
	writeln(dSlice.ptr, " ", dSlice.capacity, " ", dSlice.length);

	writeln(dArr);
	writeln(dSlice);
}

4002DFF0 3 3
4002DFF0 0 2
4002DFE0 3 3
[10, 11, 12]
[10, 11, 0]

dSlice says that it has length 2, but accessing dSlice[2] does not produce a RangeError... Likewise, printing it out prints 3 elements, not 2. This looks like a bug to me.
October 17, 2013
On 10/17/2013 11:41 AM, Vitali wrote:

> On Thursday, 17 October 2013 at 18:29:47 UTC, John Colvin wrote:
>> On Thursday, 17 October 2013 at 18:00:20 UTC, Vitali wrote:
>>> I expected slices to be in D (http://dlang.org/arrays.html) like they
>>> are in Go (http://blog.golang.org/go-slices-usage-and-internals). But
>>> they are not.
>>>
>>> Why the array have to be reallocated after the length of a slice is
>>> changed? It makes slices useless.
>>>
>>> Here a little example (it fails):
>>>
>>>  void testSlices() {
>>>    int[] dArr = [10, 11, 12];
>>>    int[] dSlice = dArr[0..2];
>>>    dSlice.length++;
>>>    assert(dArr[2]==dSlice[2]); // failure
>>>  }
>>
>> What's the use case for this? I haven't found myself ever needing
>> something like that so far, but i'd be open to seeing an example.
>
> The use case is:
>
> void appendElement(ref int[] arr, int x) {
>    arr ~= x;

That will not allocate if there is capacity.

> }
>
> void removeElement(ref int[] arr, int index) {
>    arr = arr[0..index] ~ arr[index+1..$];

It must necessarily allocate, right? How does Go deal with that case?

However, I see that the capacity of arr after that operation is just 3! Since a new array is allocated by the runtime, the capacity of arr could be larger as well.

Perhaps that's the only problem here. (?)

> }
>
> void main() {
>    int[] arr = [1, 2, 3];
>    arr.reserve(7);       // Reserve capacity.
>    arr.appendElement(4); // Here should be
>    arr.removeElement(1); // no realocation of array,
>    arr.appendElement(5); // but it is.
>    assert(arr[1] == 3);
>    assert(arr[2] == 4);
>    assert(arr[3] == 5);
> }
>
> But maybe I don't understand what slices are for in D. Anyway in Go this
> works whithout reallocation.

Ali

October 17, 2013
On Thursday, 17 October 2013 at 18:41:53 UTC, Vitali wrote:
>   arr = arr[0..index] ~ arr[index+1..$];

This line is where the reallocation happens. a ~ b on built in arrays and slices, ALWAYS allocates to ensure it doesn't stomp over some other in-use memory.

~= can extend if there's capacity, but ~ always makes a new array without modifying the input. Ali linked to the array article that explains the implementation in more detail.


The remove function should copy the data itself instead of using the ~ operator if you want it to operate in place.
October 17, 2013
> dSlice says that it has length 2,

That's before appending an element.

> but accessing dSlice[2] does not
> produce a RangeError...

That's after appending an element.

Ali

« First   ‹ Prev
1 2 3 4