Resizable Arrays?
dsimcha
dsimcha at yahoo.com
Fri Feb 27 19:51:44 PST 2009
== Quote from dsimcha (dsimcha at yahoo.com)'s article
> == Quote from Jason House (jason.james.house at gmail.com)'s article
> > Are there any good reasons to allow built in arrays to be resizable?
> > There's already plenty of empirical evidence that building arrays by appending
> is incredibly slow.
> > There are also bugs in bugzilla where resizing arrays after assigning one array
> to another violates type safety. Those bugs can be solved by always reallocatimg
> arrays when resizing, but that makes performance even worse...
> > While not much of an argument, C# also prevents array resizing.
> > Is it time to rely on standard libraries for data structures and let built in
> arrays be fixed length? It's a breaking change...
> I think that builtin arrays in D are a godsend. Resizable arrays are such an
> important, heavily used feature that they should get special treatment from the
> language, to ensure that they are syntactically elegant, efficient both at runtime
> and in terms of compilation time, easy to use, free of odd corner cases, and in
> general are true first class citizens. Nonetheless, D's arrays do have some rough
> edges. My proposal would be as follows:
> There should be two array types:
> T[new] and T[].
> This has been proposed before, though not in as much detail as what I'm
> suggesting. The semantics should work as follows:
> T[new] is considered a subtype of T[]. This works mostly like you would expect.
> T[new] can be implicitly converted to T[]. The twist is that T[] can also be
> assigned to T[new] without any explicit conversion, but a copy of the underlying
> data is implicitly made for safety.
> Assigning either a T[] or a T[new] to a T[] will result in aliasing:
> T[] foo;
> T[new] bar = new T[N];
> bar[0] = 1;
> foo = bar;
> foo[0] = 2;
> writeln(bar[0]); // Prints 2.
> T[new]s are always assigned by value to make concatenation and resizing safe. The
> underlying data is copied implicitly when assigning from a T[] to a T[new] or from
> a T[new] to another T[new].
> T[new] foo;
> T[] bar = new T[N]; // new returns T[new], using implicit conversion.
> bar[0] = 1;
> foo = bar;
> foo[0] = 2;
> writeln(bar[0]); // Prints 1.
> T[]s can be sliced, but cannot be enlarged or appended to. They should be laid
> out the same way they are now, as a struct of a pointer and a length.
> T[new]s can be appended to and enlarged in addition to being sliced. Their layout
> should be a struct of pointer, length, capacity to make appending fast. This will
> also make implicit conversion to T[] essentially free, since all that is necessary
> is slicing off the capacity field.
> I also wonder if this proposal could be extended to fix some of the covariance
> issues with arrays (see Bugzilla 2095). This might work by only allowing
> covariant types to be assigned to T[new], not T[]. For example:
> class A{}
> class B:A{}
> B[new] ba = [new B];
> A[] aa = ba; // Error: Cannot assign covariant types to T[].
> A[new] aa = ba; // Works, but copy is implicitly made.
One minor detail that I thought of: When returning a T[new] from a function, the
copying could be optimized away. If any escaping happened during the function
call, this would be either by value or as a T[] instead of a T[new]. Therefore,
at the end of a function, the only T[new] reference to the heap space in question
is guaranteed to be the T[new] that is about to be returned. Since the reference
in the callee is about to be destroyed, it can safely be returned without any copying.
More information about the Digitalmars-d
mailing list