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