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