DIP25 draft available for destruction

Chad Joan chadjoan at gmail.com
Thu Feb 7 22:28:54 PST 2013


On 02/06/2013 02:38 AM, Andrei Alexandrescu wrote:
> Probably it'll need a fair amount of tweaking. Anyhow it's in
> destroyable form.
>
> http://wiki.dlang.org/DIP25
>
>
> Thanks,
>
> Andrei

A single delegate (closure) can be used to defer both reads and writes 
on an arbitrary expression.

This works on naked variables, references, pointers, properties, and 
probably a number of other things I haven't thought of yet.

Here's the relevance to DIP25: closures already have well-defined escape 
semantics.  The downside is that they probably allocate heap way too 
aggressively in the current implementation.  The upshot is that they are 
always memory-safe.  This makes optimization a quality-of-implementation 
issue: a sufficiently intelligent compiler should be able to remove many 
allocations for non-escaping closures.

Perhaps ref parameters should be delegates under the hood instead of 
pointers?

The longterm disadvantage I see with this is the extra pointer that must 
be passed/returned.  I wonder how hard it would be for the compiler to 
instantiate specialized oldschool-pointer versions of functions with ref 
parameters whenever calls are made that do not require the guarantees 
that closures provide.

A working demonstration is given below.

Destroy!


import std.traits;
import std.stdio;

struct Option(T)
{
     bool hasValue = false;
     union
     {
         ubyte nope;
         T value;
     }

     this( T value )
     {
         hasValue = true;
         this.value = value;
     }
}

Option!T none(T)()
{
     Option!T result;
     return result;
}

/* For some reason we need to cast to this to make template deduction 
work on any functions it gets passed into. */
template DelegateRef(T)
{
     alias T delegate(Option!T intake) DelegateRef;
}

template isDelegateRef(T)
{
     static if ( isDelegate!T )
     {
         alias ReturnType!T R;
         static if ( is( T == R delegate(Option!R) ) )
             enum isDelegateRef = true;
         else
             enum isDelegateRef = false;
     }
     else
         enum isDelegateRef = false;
}

string accessor(string expr)
{
     return
         `cast(DelegateRef!(typeof(`~expr~`))) (`~
         `delegate typeof(`~expr~`)(Option!(typeof(`~expr~`)) intake) {`~
         `    if ( intake.hasValue )`~
         `        return (`~expr~` = intake.value);`~
         `    else`~
         `        return `~expr~`;`~
         `})`;
}

// Function that accepts a reference.
auto someFunc(Q)(Q qux) if ( isDelegateRef!Q )
{
     alias ReturnType!Q T;
     auto x = qux(none!T);
     x |= 0xF00D;
     qux(Option!T(x));
     return qux(none!T);
}

struct MyStruct
{
     private int m_q;

     @property int q()
     {
         writefln("get q (%x)",m_q);
         return m_q;
     }

     @property int q(int v)
     {
         writefln("set q (%x = %x)", m_q, v);
         return m_q = v;
     }
}

void testRef( ref int foo )
{
     assert(someFunc(mixin(accessor("foo"))) == 0xF00D);
}

void testPtr( int* foo )
{
     assert(someFunc(mixin(accessor("*foo"))) == 0xF00D);
}

void main()
{
     int abc = 0;
     assert(someFunc(mixin(accessor("abc"))) == 0xF00D);
     assert(abc == 0xF00D);

     int foo = 0;
     testRef(foo);
     assert(foo == 0xF00D);

     int bar = 0;
     testPtr(&bar);
     assert(bar == 0xF00D);

     MyStruct s;
     s.q = 0;
     assert(someFunc(mixin(accessor("s.q"))) == 0xF00D);
     assert(s.q == 0xF00D);
}



More information about the Digitalmars-d mailing list