Function std.exception.assumeUnique
Casts a mutable array to an immutable array in an idiomatic
manner. Technically, assumeUnique
just inserts a cast,
but its name documents assumptions on the part of the
caller. assumeUnique(arr)
should only be called when
there are no more active mutable aliases to elements of arr
. To strengthen this assumption, assumeUnique(arr)
also clears arr
before returning. Essentially assumeUnique(arr)
indicates commitment from the caller that there
is no more mutable access to any of arr
's elements
(transitively), and that all future accesses will be done through
the immutable array returned by assumeUnique
.
immutable(T)[] assumeUnique(T)
(
T[] array
) pure nothrow;
immutable(T)[] assumeUnique(T)
(
ref T[] array
) pure nothrow;
immutable(T[U]) assumeUnique(T, U)
(
ref T[U] array
) pure nothrow;
Typically, assumeUnique
is used to return arrays from
functions that have allocated and built them.
Parameters
Name | Description |
---|---|
array | The array to cast to immutable. |
Returns
The immutable array.
Example
string letters()
{
char[] result = new char['z' - 'a' + 1];
foreach (i, ref e; result)
{
e = cast(char)('a' + i);
}
return assumeUnique(result);
}
The use in the example above is correct because result
was private to letters
and the memory it referenced can no longer be written to
after the function returns. The following example shows an
incorrect use of assumeUnique
.
Bad
char[] buffer;
string letters(char first, char last)
{
if (first >= last) return null; // fine
auto sneaky = buffer;
sneaky .length = last - first + 1;
foreach (i, ref e; sneaky)
{
e = cast(char)('a' + i);
}
return assumeUnique(sneaky); // BAD
}
The example above wreaks havoc on client code because it modifies the
returned array that the previous caller considered immutable. To obtain an
immutable array from the writable array buffer
, replace
the last line with:
return to!(string)(sneaky); // not that sneaky anymore
The to
call will duplicate the array appropriately.
pure
. The following example does not
need to call assumeUnique
because the compiler can infer the
uniqueness of the array in the pure function:static string letters() pure
{
char[] result = new char['z' - 'a' + 1];
foreach (i, ref e; result)
{
e = cast(char)('a' + i);
}
return result;
}
The downside of using assumeUnique
's
convention-based usage is that at this time there is no
formal checking of the correctness of the assumption;
on the upside, the idiomatic use of assumeUnique
is
simple and rare enough to be tolerable.
Example
int[] arr = new int[1];
auto arr1 = arr .assumeUnique;
static assert(is(typeof(arr1) == immutable(int)[]));
writeln(arr); // null
writeln(arr1); // [0]
Example
int[string] arr = ["a":1];
auto arr1 = arr .assumeUnique;
static assert(is(typeof(arr1) == immutable(int[string])));
writeln(arr); // null
writeln(arr1 .keys); // ["a"]