RFC: moving forward with @nogc Phobos
via Digitalmars-d
digitalmars-d at puremagic.com
Tue Sep 30 12:50:30 PDT 2014
On Tuesday, 30 September 2014 at 19:10:19 UTC, Marc Schütz wrote:
> I'm convinced this isn't necessary. Let's take `setExtension()`
> as an example, standing in for any of a class of similar
> functions. This function allocates memory, returns it, and
> abandons it; it gives up ownership of the memory. The fact that
> the memory has been freshly allocated means that it is (head)
> unique, and therefore the caller (= library user) can take over
> the ownership. This, in turn, means that the caller can decide
> how she wants to manage it.
>
> (I'll try to make a sketch on how this can be implemented in
> another post.)
Ok. What we need for it:
1) @unique, or a way to expressly specify uniqueness on a
function's return type, as well as restrict function params by it
(and preferably overloading on uniqueness). DMD already has this
concept internally, it just needs to be formalized.
2) A few modifications to RefCounted to be constructable from
unique values.
3) A wrapper type similar to std.typecons.Unique, that also
supports moving. Let's called it Owned(T).
4) Borrowing.
setExtension() can then look like this:
Owned!string setExtension(in char[] path, in char[] ext);
To be used:
void saveFileAs(in char[] name) {
import std.path: setExtension;
import std.file: write;
name. // scope const(char[])
setExtension("txt"). // Owned!string
write(data);
}
The Owned(T) value implicitly converts to `scope!this(T)` via
alias this; it can therefore be conveniently passed to
std.file.write() (which already takes the filename as `in`)
without copying or moving. The value then is released
automatically at the end of the statement, because it is only a
temporary and is not assigned to a variable.
For transferring ownership:
RefCounted!string[] filenames;
// ...
filenames ~= name.setExtension("txt").release;
`Owned!T.release()` returns the payload as a unique value, and
resets the payload to it's init value (in this case `null`).
RefCounted's constructor then accepts this unique value and takes
ownership of it. When the Owned value's destructor is called, it
finds the payload to be null and doesn't free the memory.
Inlining and subsequent optimization can turn the destructor into
a no-op in this case.
Optionally, Owned!T can provide an `alias this` to its release
method; in this case, the method doesn't need to be called
explicitly. It is however debatable whether being explicit with
moving isn't the better choice.
More information about the Digitalmars-d
mailing list