On Wednesday, 9 January 2013 at 12:38:13 UTC, Jonathan M Davis wrote:

When you append to array, the elements being added are in untyped memory. So,
no mutation of immutable anything is going on at all.

Ok, I guess that makes sense.

I don't know what Appender is doing, but casting away immutable and mutating anything is undefined behavior. However, if you _know_ that the data is actually mutable, then you can get away with it. It's still technically undefined behavior though. Pretty much the only place that it would make sense to do that that I can think of is with std.concurrency, but again, I don't
know what Appender is doing.

Hum...

Appender uses "arr.length = arr.capacity" so as to mark the array as "used" so that if anybody tries to append to the array, it will not interfere with appender. Does this operation "make the memory typed"?

Here is a reduced test case of what appender does

http://dpaste.dzfl.pl/d8fce486

//----
import std.stdio;

void main()
{
    //The initial array
    immutable(int)[] arr1 = [0, 1, 2, 3];

    //The same array, aliased as mutable;
    int[] arr2 = cast(int[])arr1;

//Change underlying range size so that other appends to arr1 cause relocation
    size_t capacity = arr1.capacity;
    if (capacity > arr1.length)
    {
        auto tmp = arr2;
        tmp.length = tmp.capacity;
        assert(arr2.ptr == tmp.ptr);
        assert(arr1.capacity == 0);
    }
    else
assert(0); //To make sure we are actually testing something

    //Write to the not yet written but reserved to zone
    for ( ; arr2.length < capacity; )
    {
        immutable len = arr2.length;
        arr2.ptr[len] = cast(int)len; //HERE
        arr2 = arr2.ptr[0 .. len + 1];
    }

    //Check arr2
    writeln(arr2);
}
//----

The original line I am concerned about is "HERE": Is this a legal mutation?

On topic, the actual code in Appender looks like this
//----
//Type of item is "U", with "isImplicitlyConvertible!(U, T)"
_data.arr.ptr[len] = cast(Unqual!T)item;
//----
Worth noting is:
* This will bigtime fail if T has a constructor (should use emplace).
* Also, is that cast even legal?

If emplace is able to modify the user provided immutable array, then wouldn't it be better off storing an actual "T[]" (instead of (Unqual!T)[]): This would avoid any abusive use of casts, and preserve the qualified type, right?

Reply via email to