Jump to page: 1 2 3
Thread overview
[Article Contest, first draft] D Slices
May 18, 2011
David Gileadi
May 18, 2011
Andrej Mitrovic
May 18, 2011
Andrej Mitrovic
May 18, 2011
Jesse Phillips
May 18, 2011
Andrej Mitrovic
May 18, 2011
Jesse Phillips
May 19, 2011
Jonathan M Davis
May 19, 2011
Jesse Phillips
May 19, 2011
Jonathan M Davis
May 18, 2011
Alex_Dovhal
May 18, 2011
Johann MacDonagh
May 20, 2011
Jens Mueller
May 23, 2011
Jonathan M Davis
May 18, 2011
Having seen quite a few incorrect descriptions of how D slices work (particularly regarding appending), I wrote an article that tries to describe how D slices work, and why they behave the way they do.

Being one of the only places where I have web space, it's on my dcollections site, I probably will move it to the D wiki eventually, but I'm much more familiar with the Trac wiki syntax.

Please, if you have any comments or recommendations, let me know.  I certainly am no author, so I probably screwed a few things up :)

http://www.dsource.org/projects/dcollections/wiki/ArrayArticle

Thanks

-Steve
May 18, 2011
On 5/18/11 11:03 AM, Steven Schveighoffer wrote:
> Please, if you have any comments or recommendations, let me know.

First off, this is a fantastic article.  Thanks for clearly explaining a fairly subtle concept.  I'm especially happy to finally understand how appending to a slice can avoid reallocating and what assumeSafeAppend does.

I do have a couple of nits:

1. After the shrinkTo2 example, you say "This might look like you changed the passed arr's length to 2, but it actually did not affect anything," followed by the reason.  It took me a bit to realize why this was so.  I think it would be clearer if the example included the call to shrinkTo2, e.g.

void shrinkTo2(int[] arr)
{
    if(arr.length > 2)
        arr.length = 2;
}

int[] a = new int[5];
shrinkTo2(a);

And then you pointed out that a's length hasn't changed after the call.  Including the calling code might also be helpful for the Determinism example, for the same reason.

2. In the section "A Slice You Can Append On" the phrase "The slice does not own it's data" should remove the apostrophe from "its".  There is at least one other place in the document that also make this mistake, under the Caching section.

Again, fantastic article.

-Dave
May 18, 2011
On Wed, 18 May 2011 14:44:33 -0400, David Gileadi <gileadis@nspmgmail.com> wrote:

> On 5/18/11 11:03 AM, Steven Schveighoffer wrote:
>> Please, if you have any comments or recommendations, let me know.
>
> First off, this is a fantastic article.  Thanks for clearly explaining a fairly subtle concept.  I'm especially happy to finally understand how appending to a slice can avoid reallocating and what assumeSafeAppend does.

Thanks!

>
> I do have a couple of nits:
>
> 1. After the shrinkTo2 example, you say "This might look like you changed the passed arr's length to 2, but it actually did not affect anything," followed by the reason.  It took me a bit to realize why this was so.  I think it would be clearer if the example included the call to shrinkTo2, e.g.
>
> void shrinkTo2(int[] arr)
> {
>      if(arr.length > 2)
>          arr.length = 2;
> }
>
> int[] a = new int[5];
> shrinkTo2(a);
>
> And then you pointed out that a's length hasn't changed after the call.   Including the calling code might also be helpful for the Determinism example, for the same reason.

OK, thanks, I'll do that.

>
> 2. In the section "A Slice You Can Append On" the phrase "The slice does not own it's data" should remove the apostrophe from "its".  There is at least one other place in the document that also make this mistake, under the Caching section.

Yes, its a problem I have ;)

-Steve
May 18, 2011
On 5/18/11, David Gileadi <gileadis@nspmgmail.com> wrote:
> There is at least one other place in the document that also make this mistake.
The first sentence! :]
May 18, 2011
On Wed, 18 May 2011 14:44:33 -0400, David Gileadi <gileadis@nspmgmail.com> wrote:

> I do have a couple of nits:
>

Fixed

-Steve
May 18, 2011
Well consider me enlightened. From all the things I've read before this article, I thought a slice is a special feature that is only introduced when you take an [n..m] from an array, e.g. my understanding was something like:

int[] a = new int[5];  // a is definitely a dynamic array
auto b = a[1..3];  // take a slice and make b an array of length 2,
pointing at a[1..3];

Where "making an array" would just mean creating a new struct with a pointer and a length, not allocating memory for the elements.

Your article should have been in TDPL. Good work!

It might be a good idea to mention how you can take a slice of a static array to make it passable to functions which expect slices. A lot of functions (all of them?) in Phobos expect slices and not static arrays, but it's not at all obvious.

E.g. if you try to do this it will fail to compile with an extremely
ugly message:
    int[4] arr1 = [ 1, 2, 3, 4 ];
    auto mapped = map!("a + a")(arr1);

testmap.d(10): Error: template std.algorithm.map!("a + a").map(Range)
if (isInputRange!(Unqual!(Range))) does not match any function
template declaration
testmap.d(10): Error: template std.algorithm.map!("a + a").map(Range)
if (isInputRange!(Unqual!(Range))) cannot deduce template function
from argument types !()(int[4u])

All that has to be done is to take a slice:
    int[4] arr1 = [ 1, 2, 3, 4 ];
    auto mapped = map!("a + a")(arr1[]);

Come to think of it, these types of errors could be caught by the compiler to output a nicer error message, imo.
May 18, 2011
Steven Schveighoffer Wrote:

> Having seen quite a few incorrect descriptions of how D slices work (particularly regarding appending), I wrote an article that tries to describe how D slices work, and why they behave the way they do.

Still reading, but the example should use assertions which pass:

void main()
{
   int[] arr = new int[5];
   shrinkTo2(arr);
   assert(arr.length != 2); // Not expected!
}

It is good form because reading it will describe the outcome even without comment.
May 18, 2011
"Steven Schveighoffer" <schveiguy@yahoo.com> ÓÏÏÂÝÉÌ/ÓÏÏÂÝÉÌÁ × ÎÏ×ÏÓÔÑÈ ÓÌÅÄÕÀÝÅÅ: news:op.vvou3fbgeav7ka@localhost.localdomain...
> Having seen quite a few incorrect descriptions of how D slices work (particularly regarding appending), I wrote an article that tries to describe how D slices work, and why they behave the way they do.
>
> Being one of the only places where I have web space, it's on my dcollections site, I probably will move it to the D wiki eventually, but I'm much more familiar with the Trac wiki syntax.
>
> Please, if you have any comments or recommendations, let me know.  I certainly am no author, so I probably screwed a few things up :)
>
> http://www.dsource.org/projects/dcollections/wiki/ArrayArticle
>
> Thanks
>
> -Steve
>

Nice article, very pleasured to read. One thing that strained my mind - this exaple:

>import std.stdio;
>
>char[] fillAs(char[] buf, size_t num)
>{
>   if(buf.length < num)
>      buf.length = num; // increase buffer length to be able to hold the
> A's
>   buf[0..num] = 'A';   // assign A to all the elements
>   return buf[0..num];  // return the result
>}
>
>void main()
>{
>   char[] str = new char[10];   str[] = 'B';
>   fillAs(str, 20);     // buffer must be reallocated
>   writeln(str);        // "BBBBBBBBBB"
(1)
>   fillAs(str, 12);     // buffer can be extended in place!
>   writeln(str);        // "AAAAAAAAAA";
>}

Please add in (1) assert(str.capacity == 15);




May 18, 2011
On Wed, 18 May 2011 16:22:50 -0400, Andrej Mitrovic <andrej.mitrovich@gmail.com> wrote:

> Well consider me enlightened. From all the things I've read before
> this article, I thought a slice is a special feature that is only
> introduced when you take an [n..m] from an array, e.g. my
> understanding was something like:
>
> int[] a = new int[5];  // a is definitely a dynamic array
> auto b = a[1..3];  // take a slice and make b an array of length 2,
> pointing at a[1..3];
>
> Where "making an array" would just mean creating a new struct with a
> pointer and a length, not allocating memory for the elements.

D1 actually had almost this notion -- any slice that started at the beginning of a block was considered the "owner" slice.  The only issue was, you could have several slices think they own the data, which leads to bad things if you append to more than one of them.  This is where the "stomping" issue came in.  We all just dealt with it.

> Your article should have been in TDPL. Good work!

Thanks!

>
> It might be a good idea to mention how you can take a slice of a
> static array to make it passable to functions which expect slices. A
> lot of functions (all of them?) in Phobos expect slices and not static
> arrays, but it's not at all obvious.

This is a good idea, I should probably add to the section that demonstrates slices to show how slicing can be used on things other than heap-allocated arrays (although I allude to that in one part).

> E.g. if you try to do this it will fail to compile with an extremely
> ugly message:
>     int[4] arr1 = [ 1, 2, 3, 4 ];
>     auto mapped = map!("a + a")(arr1);
>
> testmap.d(10): Error: template std.algorithm.map!("a + a").map(Range)
> if (isInputRange!(Unqual!(Range))) does not match any function
> template declaration
> testmap.d(10): Error: template std.algorithm.map!("a + a").map(Range)
> if (isInputRange!(Unqual!(Range))) cannot deduce template function
> from argument types !()(int[4u])
>
> All that has to be done is to take a slice:
>     int[4] arr1 = [ 1, 2, 3, 4 ];
>     auto mapped = map!("a + a")(arr1[]);

This is really more of a problem with map and IFTI than arrays.  The error message is actually accurate (a fixed-sized array is not a range).

What would be nice is to say, "if map is called with a static array, slice it first".  I think you would probably need some sort of wrapper call:

auto map(alias pred, T)(ref T t) if(isStaticArray!T)
{
   return map!(pred)(t[]);
}

But you'd have to do this for every template function that takes a range.

I don't know of a better way the compiler could do it, IFTI is very simple when it comes to interpreting what argument type it should use.

-Steve
May 18, 2011
On Wed, 18 May 2011 16:37:49 -0400, Jesse Phillips <jessekphillips+D@gmail.com> wrote:

> Steven Schveighoffer Wrote:
>
>> Having seen quite a few incorrect descriptions of how D slices work
>> (particularly regarding appending), I wrote an article that tries to
>> describe how D slices work, and why they behave the way they do.
>
> Still reading, but the example should use assertions which pass:
>
> void main()
> {
>    int[] arr = new int[5];
>    shrinkTo2(arr);
>    assert(arr.length != 2); // Not expected!
> }
>
> It is good form because reading it will describe the outcome even without comment.

I always wonder about that.  One of the issues with assert for people "feeling" out the language is, a passing assert doesn't seem to do anything.

For instance, in this example, if you take the code I wrote, and compile it, you'll get a loud assertion error (proving the assertion runs and fails).

If you take your code and run it, you get a command prompt.  It doesn't really help you see how it works.

I'm contemplating switching it to a writeln instead ;)

-Steve
« First   ‹ Prev
1 2 3