An important potential change to the language: transitory ref

Steven Schveighoffer schveiguy at yahoo.com
Fri Mar 19 20:20:59 PDT 2010


On Fri, 19 Mar 2010 22:56:59 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> Hello,
>
>
> Walter and I are mulling over an idea that may turn out to be extremely  
> interesting for D.
>
> Consider the following desideratum: D is a garbage-collected language,  
> but we want to be able to define "completely encapsulated" types. That  
> means types that never escape pointers to their internal data. If we  
> manage to do so, then the type can manage memory any way it desires.
>
> Consider the case of a simple container, e.g. an array. If we manage to  
> convince the array to never "leak" a reference to an element, the array  
> is free to deallocate memory as it wishes.
>
> One way to achieve that is by simply having the array type return  
> rvalues. That is (stylized code below for a type Array!T) instead of:
>
> ref T opIndex(size_t index);
>
> we'd have
>
> T opIndex(size_t index);
>
> and so on. That way nobody can escape a pointer to stuff pointing into  
> the array, so the array is safe and can reallocate memory whenever it  
> wishes without fearing that someone has squirreled a pointer to its  
> buffer.
>
> I'm encouraged that Scott Meyers' Effective C++ topic 'Avoid returning  
> "handles" to internal data' talks essentially about that.
>
> Of course, the problem is that you now can't change stuff inside the  
> array. Also there is an efficiency issue.
>
> So I was thinking of the following: how about still returning a  
> reference, but define a rule in the language that references can't  
> escape - you can't take their address and squirrel it away; the only  
> thing you can do is use them right on the spot or pass them down to  
> functions.
>
> Essentially that means: "I'm giving you the address of the object, but  
> in a scoped manner - there's nothing you can do to save it beyond the  
> current expression."
>
> To clarify, for an Array!T object, you can do:
>
> arr[5] = obj;
>
> but you can't do:
>
> T* p = & arr[5];
>
> The former uses the reference anonymously right there, and the latter is  
> verboten because it could potentially escape "p" outside the current  
> expression, and an array resize would leave p dangling.
>
> Are we hamstringing the language in a way that would disable important  
> idioms?

What about returning refs that are ref returns or part of other refs?  For  
example:

ref int foo(ref int x)
{
    return x;
}

ref int bar()
{
   int x;
   return foo(x);
}

The reason I bring this up is because it's exactly what a struct is  
doing.  Basically, the problem is not so much that you cannot squirrel it  
away, but you can return it out of the stack scope it was allocated on.  I  
don't know if there's a way to fix this without restricting struct members  
 from returning ref items.

For instance, try to find a rule that prevents the above from compiling,  
but allows the following to compile.

struct S
{
    private int x;
    ref int getX() { return x;}
}

struct T
{
   S s;
   ref int getSX() { return s.x; }
}

-Steve



More information about the Digitalmars-d mailing list