T[new] misgivings

Jeremie Pelletier jeremiep at gmail.com
Thu Oct 15 20:51:04 PDT 2009


Andrei Alexandrescu wrote:
> I talked to Walter about T[new] today and it seems we are having a 
> disagreement.
> 
> The problem is that I believe T[new] is a container, whereas Walter 
> believes T[new] is nothing but a slice with a couple of extra operations.

I agree with the container model, it should work the way 
std.array.Appender does right now. T[new] would be used when you need to 
grow the array, and t[] when the size is final.

> Paradoxically this seems to be conducive to subtle efficiency issues. 
> For example, consider:
> 
> int[new] a;
> ...
> a = [1, 2, 3];
> 
> What should that do?
> 
> Walter: T[new] is a slice with benefits, assignment for slices rebinds 
> the slice, therefore the assignment must do the same. In this case, the 
> assignments allocate a new array and make a refer to that array. 
> Whatever old array a referred to will continue to live wherever it was.
> 
> Me: T[new] is a container, therefore the assignment must resize the 
> container from whatever size it had to 3 and then write 1, 2, 3 to its 
> three slots.

I think Walter wants to keep the syntax consistent with slices, even if 
T[new] is a container, it would just mean "assign this new slice to the 
container".

> I guess each of us has a point, but this is a setup for an increasingly 
> unpleasant situation. Here's the dialog as it happened.
> 
> A: Ok, then how do I say the common operation "I want to overwrite 
> whatever the array had with 1, 2, 3"? I can only presume there must be 
> an obvious and simple way to do so, and I thought a = [1, 2, 3] was the 
> obvious syntax to achieve that.
> 
> W: No, you must write
> 
> a[] = [1, 2, 3];
> 
> A: But that only works if the container already had length 3. So what I 
> need to do is this:
> 
> a.length = 3;
> a[] = [1, 2, 3];
> 
> A: But that is inefficient if the array had length less than 3 because 
> it means double assignment

If the array is of type T[new] then the runtime implementation 
(_d_array_new_assign?) would take care of resizing the array. As opposed 
to slices which can't add/remove memory from arrays anymore. You 
therefore wouldn't need to set the length before assignments.

> W: Nobody complained about it with slices.
> 
> A: So if I do want something that does the obvious operation "Whatever 
> that array had, make it now have 1, 2, 3 as it contents" at a reasonable 
> cost I need to call an elaborate function that is highly nontrivial to 
> write?
> 
> W: Looks like so.

Why would you need a nontrivial function? It's all hidden in the 
compiler runtime implementation, which would just get uninitialized 
memory if needed and then copy the assignment, its fairly simple.

> A: So then the first "Effective D" standard would have Item #1: "Avoid 
> assignment to arrays. Call the assign() function"?
> 
> W: Nobody complained about it with slices.
> 
> ===============
> 
> This goes into something more interesting that I thought of after the 
> conversation. Consider:
> 
> T[new] a;
> T[] b;
> ...
> a = b;
> 
> What should that do?

Raise a compiler error, its unsafe because its unknown of b is an entire 
array (so .ptr is a valid GC root) or a slice.

T[new] would implicitly cast to T[] but the opposite requires a cast.

T[new] a;
T[] b;

a = cast(T[new])b; // safe because we assume b.ptr is a valid gc root
a = b.dup; // safe because the compiler can infer its a gc root

Jeremie



More information about the Digitalmars-d mailing list