On Wednesday, 6 February 2013 at 07:38:17 UTC, 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

All of the 'fine' ones are fine. Which leaves how one might invoke the 'unfine' ones. The language must make a choice between restricted simplicity and flexible complexity. If it chooses flexibility, the function signature must give a clue as to what the return value contains. 'out' return values and 'scope' parameters will give the clues it needs.

Here are all the 'unfine' functions listed:

ref T gun(ref T);
struct S { int a; T b; }
ref S iun(ref S);

ref T caller(bool condition, ref T v1, ref S v2, T v3, S v4) {
    T v5;
    S v6;

    // Not fine, bound to locals
    // if (condition) return gun(v3);
    // if (condition) return gun(v4.b);
    // if (condition) return gun(v5);
    // if (condition) return gun(v6.b);

    // Not fine, bound to locals
    // if (condition) return iun(v4);
    // if (condition) return iun(v6);
}

Say gun's actual implementation is:

ref T gun(ref T a) {
   auto noo = new T;
   noo = a;
   return noo;
}

You can' tell from the function signature that the return value of this function is good to go, so the call 'return gun(v3);' above would be disallowed even though it didn't need to be. If you marked the signature with 'out', the caller knows it's good to go, and the compiler can statically prevent the function from returning one of its ref parameters. 'out' can be made to imply 'ref' in any case where the type is not inherently a reference anyway.

out T gun(ref T a) {
   return new T; // Pass
   return a; // Error
}

This will solve all problems, except for the very rare corner case when you need to assert fined-grained control over exactly which ref parameters are safe and which are not. 'scope' comes to the rescue here.

ref int fud(ref int a, scope int b) {
   a += b;
   return a; // Pass

   return b; // Error
}
ref int elmer(ref int f) {
   int v;
   return fud(f, v); // Passes
   return fud(v, f); // Fails
}

An 'out' return value simply marks all its 'ref' parameters 'scope' underneath the hood, so there will never be a need for both 'out' and 'scope' in the same signature. Since 'scope' is useless if its not a reference, it implies 'ref' also.

I'm pretty sure this is the best way to make the language completely flexible. I don't anticipate an easier way to get it done, and therefore, to my mind at least, the choice is between simple-but-limited and flexible-and-complicated.

Reply via email to