Flexibly sized arrays (was Re: in-parameter)

Steven Schveighoffer schveiguy at yahoo.com
Mon Nov 8 11:38:48 PST 2010


On Mon, 08 Nov 2010 14:19:47 -0500, Pillsy <pillsbury at gmail.com> wrote:

> Steven Schveighoffer Wrote:
>
>> On Mon, 08 Nov 2010 13:46:52 -0500, Pillsy <pillsbury at gmail.com>
>> wrote:
>
>> > Besides, isn't catenating or appending in place impossible with D's
>> > (immutable) strings anyway?
>
>> This is a misconception, a string is not immutable, the data it points
>> to is immutable.  You can append to a string just like a mutable array.
>
> So, wait, if I have a program like this:
>
> void appendSailor (string s) {
>    s ~= "Sailor";
> }
>
> void main () {
>    auto s = "Hello World!";
>
>    appendSailor(s[0 .. 6]);
>
>    writefln(s);
> }
>
> I should expect to get "Hello Sailor" as output? Or is it just that a  
> new array of characters will be allocated and that will be appended  
> into, so `appendSailor()` becomes a slightly expensive no-op?

The latter. appendSailor does nothing of significance since it throws away  
its result.

> The former behavior would be really horrible, while the latter behavior  
> doesn't seem to provide an overwhelming advantage over not allowing  
> append-in-place for arrays.

It provides huge value, because given a string, I don't have to care where  
it came from or who built it, I know I can just append to it and the  
runtime takes care of the details.  When it can be optimized, it will be.   
Less things to care about = less things to prove.  By disallowing  
appending, you are wasting huge amounts of possible optimizations (didn't  
follow this thread fully, so I'm not sure exactly what you proposed).

For instance, if you had:

string appendSailor (string s) {
    s ~= "Sailor";
    return s;
}

void main()
{
    auto s = "Hello World!";
    auto s2 = "Hello ";
    auto s3 = s2.idup;
    auto s4 = s.idup;

    s = appendSailor(s[0..6]);
    s2 = appendSailor(s2);
    s3 = appendSailor(s3);
    s4 = appendSailor(s4[0..6]);
}

all four cases are valid, the only one that "extends into existing memory"  
is s3, but it's the only one where you *could* extend into existing  
memory.  s and s2 are in ROM, so you can't extend there, extending  
s4[0..6] would overwrite immutable data, so that is illegal.  So  
basically, appending optimizes where it possibly can optimize, and  
everywhere else it does the right thing to complete the operation.

So without knowing how appendSailor is called, I can judge it just by  
looking at appendSailor, and reason that it will always return a  
consistent result, with no memory violations.  In addition, I need not  
specify any extra requirements for appendSailor like "only call this with  
newly allocated memory!".  It just works, the same way, every time.

This of course is only true for immutable or const.  For mutable data,  
there is the possibility that a function may create a confusing situation,  
but it's very rare for this to happen, since most code is either concerned  
with appending data or modifying data, but not both.

-Steve


More information about the Digitalmars-d mailing list