Example:
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:
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.
Note
Checking for uniqueness during compilation ispossible in certain cases, especially when a function is marked (or inferred) as pure. The following example does not need to call assumeUnique because the compiler can infer the uniqueness of the array in the pure function:
string letters() pure { char[] result = new char['z' - 'a' + 1]; foreach (i, ref e; result) { e = cast(char)('a' + i); } return result; } ----
For more on infering uniqueness see the unique and
lent keywords in the ArchJavalanguage.
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.