resizeable arrays: T[new]
Walter Bright
newshound1 at digitalmars.com
Mon Jun 4 10:40:01 PDT 2007
Frits van Bommel wrote:
> Walter Bright wrote:
>> Now, it turns out that it is very rare for a function to legitimately
>> want to resize a buffer passed to it. So we finally hit on the idea of
>> making a resizeable array a different type, say:
>>
>> T[n] a; // static array
>> T[] b; // dynamic array
>> T[new] c; // resizeable array
>>
>> a.length = 6; // error, static array
>> b.length = 6; // error, dynamic array is not resizeable
>> c.length = 6; // ok
>> b = c; // ok, implicit conversion of resizeable to dynamic
>> c = b; // error
>> c = b[0..n]; // error
>> b = c[0..n]; // ok, but watch out if c is later resized
>> b = c[0..n].dup; // ok, no worries
>> c = cast(T[new])b; // ok, but this will be deliberate
>
> What about
> c = a;
> ?
Good question. That'll be allowed. I have a couple misgivings about it,
though.
> I have several places where I have functions that follow this pattern:
> ---
> T[] foo(<parameters>, T[] buffer = null) {
> buffer.length = <something>;
> <fill buffer>
> return buffer;
> }
> ---
> These are intended to be usable with "buffer" being either a
> stack-allocated static array or a heap-allocated dynamic array. If the
> passed buffer is big enough a slice is returned, otherwise it gets
> enlarged (and possibly reallocated on the heap).
> I guess with this proposed modification I'd want to accept and return a
> "T[new]", but will that allow static arrays (stack-allocated) to be
> passed in?
Yes.
> I'd hate to have to write two different functions, one for static arrays
> and slices and one for resizable arrays... (and I'm not fond of the idea
> of extra casts to make it work with a single function)
>
> Also, I often write toString() members of objects (and other functions
> returning strings) like this:
> ---
> char[] toString() {
> auto ret = "prefix";
> foreach (elt; children) {
> ret ~= elt.toString();
> // perhaps append a separator here
> }
> // if separators were appended, remove the last one here
> ret ~= "postfix";
> return ret;
> }
> ---
> Will these need to be changed? (probably a .dup after the "prefix" string)
> (Since string constants are also static arrays, this is the same basic
> issue as above)
You'd need to rewrite it as:
---
string toString() {
invariant(char)[new] ret = "prefix";
foreach (elt; children) {
ret ~= elt.toString();
// perhaps append a separator here
}
// if separators were appended, remove the last one here
ret ~= "postfix";
return ret;
}
---
since the type of "prefix" will be invariant(char)[6];
You'll need to use "string" as a return type, because you'll potentially
be returning a reference to an immutable string literal, and that must
be reflected in the type. If you chose to do "prefix".dup, it could be
written as:
---
string toString() {
auto ret = "prefix".dup;
foreach (elt; children) {
ret ~= elt.toString();
// perhaps append a separator here
}
// if separators were appended, remove the last one here
ret ~= "postfix";
return ret;
}
---
and the return type could be either string or char[]. The type of ret
here will be char[new], as that is what .dup will return.
>> I think this will entail only very rare changes to user code, but will
>> be a big improvement in type safety. Note that it will *still*
>> possible for array resizing to affect other slices into the same
>> array, but it's far, far less likely to happen inadvertently. The
>> attractiveness of this solution is it nearly completely solves the
>> problem with zero runtime cost.
>
> I think I may need to make quite some changes actually, though the
> changes required to the latter code sample I gave will be minimal.
>
>
> Another question, will the following be allowed:
> ---
> class Base {
> abstract char[] foo();
> }
>
> class Derived : Base {
> override char[new] foo() { assert(0, "Not implemented yet"); }
> }
> ---
> ?
Yes, since char[new] can be implicitly converted to char[]. The reverse
will not work.
More information about the Digitalmars-d-announce
mailing list