On Mon, 09 Feb 2009 06:39:36 +0300, Andrei Alexandrescu 
<seewebsiteforem...@erdani.org> wrote:

Hey,


I've been doing a hecatomb of coding in D lately, and had an insight that I think is pretty cool. Consider:

struct Widget
{
     private Midget * m;
     ...
     this(ref Midget mdgt) { m = &mdgt; ... }
}

It's a rather typical pattern in C++ for forwarding objects that need to store a reference/pointer to their parent and also nicely warn their user that a NULL pointer won't do.

But I'm thinking this is unduly dangerous because the unwitting user can easily get all sorts of wrong code to compile:

Widget makeACoolWidget()
{
     Midget coolMidget;
     return Widget(coolMidget); // works! or...?
}

The compiler's escape detection mechanism can't help quite a lot here because the escape hatch is rather indirect.

Initially I thought SafeD should prevent such escapes, whereas D allows them. Now I start thinking the pattern above is dangerous enough to be disallowed in all of D. How about this rule?

***************
Rule: ref parameters are PASS-DOWN and RETURN only. No escaping of addresses of ref parameters is allowed. If you want to escape the address of a ref parameter, use a pointer in the first place.
***************

This rule is powerful and leads to an honest style of programming: if you plan on escaping some thing's address, you make that clear in the public signature. The fix to the idiom above is:

struct Widget
{
     private Midget * m;
     ...
     this(Midget * mdgt) { enforce(mdgt); m = mdgt; ... }
}

Widget makeACoolWidget()
{
     auto coolMidget = new Midget;
     return Widget(coolMidget); // works!
}

Whaddaya think?


Andrei

I agree. It also grants safe way to pass temporaries:

int bar();
int* gi;
void foo(ref int i)
{ gi = &i;
}

foo(bar()); // unsafe

Reply via email to