RFC: moving forward with @nogc Phobos

Andrei Alexandrescu via Digitalmars-d digitalmars-d at puremagic.com
Wed Oct 1 01:55:58 PDT 2014


On 9/30/14, 9:10 AM, Sean Kelly wrote:
> On Monday, 29 September 2014 at 10:49:53 UTC, Andrei Alexandrescu wrote:
>>
>> The policy is a template parameter to functions in Phobos (and
>> elsewhere), and informs the functions e.g. what types to return.
>> Consider:
>>
>> auto setExtension(MemoryManagementPolicy mmp = gc, R1, R2)(R1 path, R2
>> ext)
>> if (...)
>> {
>>     static if (mmp == gc) alias S = string;
>>     else alias S = RCString;
>>     S result;
>>     ...
>>     return result;
>> }
>
> Is this for exposition purposes or actually how you expect it to work?

That's pretty much what it would take. The key here is that RCString is 
almost a drop-in replacement for string, so the code using it is almost 
identical. There will be places where code needs to be replaced, e.g.

auto s = "literal";

would need to become

S s = "literal";

So creation of strings will change a bit, but overall there's not a lot 
of churn.

> Quite honestly, I can't imagine how I could write a template function
> in D that needs to work with this approach.

You mean write a function that accepts a memory management policy, or a 
function that uses one?

> As much as I hate to say it, this is pretty much exactly what C++
> allocators were designed for.  They handle allocation, sure, but they
> also hold aliases for all relevant types for the data being allocated.
> If the MemoryManagementPolicy enum were replaced with an alias to a type
> that I could use to at least obtain relevant aliases, that would be
> something.  But even that approach dramatically complicates code that
> uses it.

I think making MemoryManagementPolicy a meaningful type is a great idea. 
It would e.g. define the string type, so the code becomes:

auto setExtension(alias MemoryManagementPolicy = gc, R1, R2)(R1 path, R2 
ext)
if (...)
{
     MemoryManagementPolicy.string result;
     ...
     return result;
}

This is a lot more general and extensible. Thanks!

Why do you think there'd be dramatic complication of code? (Granted, at 
some point we must acknowledge that some egg breaking is necessary for 
the proverbial omelette.)

> Having written standards-compliant containers in C++, I honestly can't
> imagine the average user writing code that works this way. Once you
> assert that the reference type may be a pointer or it may be some
> complex proxy to data stored elsewhere, a lot of composability pretty
> much flies right out the window.

The thing is, again, we must make some changes if we want D to be usable 
without a GC. One of them is e.g. to not allocate built-in slices all 
over the place.

> For example, I have an implementation of C++ unordered_map/set/etc
> designed to be a customizable cache, so one of its template arguments is
> a policy type that allows eviction behavior to be chosen at declaration
> time.  Maybe the cache is size-limited, maybe it's age-limited, maybe
> it's a combination of the two or something even more complicated.  The
> problem is that the container defines all the aliases relating to the
> underlying data, but the policy, which needs to be aware of these, is
> passed as a template argument to this container.
>
> To make something that's fully aware of C++ allocators then, I'd have to
> define a small type that takes the container template arguments (the
> contained type and the allocator type) and generates the aliases and
> pass this to the policy, which in turn passes the type through to the
> underlying container so it can declare its public aliases and whatever
> else is true standards-compliant fashion (or let the container derive
> this itself, but then you run into the potential for disagreement). And
> while this is possible, doing so would complicate the creation of the
> cache policies to the point where it subverts their intent, which was to
> make it easy for the user to tune the behavior of the cache to their own
> particular needs by defining a simple type which implements a few
> functions.  Ultimately, I decided against this approach for the cache
> container and decided to restrict the allocators to those which defined
> a pointer to T as T* so the policies could be coded with basically no
> knowledge of the underlying storage.

That sounds like a rather involved artifact. Hopefully we can leverage 
D's better expressiveness to make building such complex libraries easier.

> So... while I support the goal you're aiming at, I want to see a much
> more comprehensive example of how this will work and how it will affect
> code written by D *users*.

Agreed.

> Because it isn't enough for Phobos to be
> written this way.  Basically all D code will have to take this into
> account for the strategy to be truly viable.  Simply outlining one of
> the most basic functions in Phobos, which already looks like it will
> have a static conditional at the beginning and *need to be aware of the
> fact that an RCString type exists* makes me terrified of what a
> realistic example will look like.

That would be overreacting :o).


Andrei



More information about the Digitalmars-d mailing list