Steven Schveighoffer wrote:
On Mon, 10 Aug 2009 14:38:24 -0400, Stewart Gordon <[email protected]>
wrote:
Since nobody's yet asked....
What type would .dup and .idup return?
The best choice I can see is to make .dup return T[new] and .idup
return invariant(T)[].
This brings up another question. Should something like
immutable(T)[new] or const(T)[new] be even valid? Consider this:
immutable(char)[new] str = "hello".idup; // not sure how you convert a
literal to an array, but assume it works for now.
assert(str.capacity == 16); // assume GC still allocates 16 minimum blocks
str ~= " there";
auto slice = str[5..$];
str.length = 5;
str ~= " world";
assert(slice == " there"); // fails?
We most likely have the same issue here with immutable data as we do
today, just not as obvious. Although it's a corner case, it does
violate immutability without casts.
There are several options:
1. immutable(T)[new] and const(T)[new] are invalid. This limits us more
than the current regime, but is a questionable construct to begin with,
considering it allows appending in place (you can always create a new
array with concatenation).
2. immutable(T)[new] and const(T)[new] are equivalent to
immutable(T[new]) and const(T[new]) respectively. This simplifies
generic programming and still prevents abuses.
3. when you shrink an array of immutable/const elements' length, the
capacity automatically shrinks to prevent overwriting previous data.
This still leaves mutable data with the overwrite problem, but it
doesn't violate const.
4. same as #3 but do it for both immutable or mutable arrays.
Also, implicit casting to const needs to be addressed, normally you
can't do this with templated types (if that's how the underlying type is
implemented).
I think 1 is a good option. Essentially you can't have a resizeable
array of immutable data. Functional languages don't have such a thing.
If we go for (3), code that looks tighter is in fact more wasteful as
every shrinking+expanding cycle causes a new allocation and a copy.
Andrei