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?