search of a workaround

monarch_dodra monarchdodra at gmail.com
Fri Feb 8 15:10:37 PST 2013


On Friday, 8 February 2013 at 21:06:27 UTC, Namespace wrote:
> I've been thinking about the lack of rvalue references. 
> Therefore, I would like to know what you think is the best 
> workaround for this feature.
> I illustrate below the only (*) five solutions briefly and 
> summarized.
> What do you think is the best? Which of these do you use? Or 
> did I forget some possible solutions?
> I'm looking for this for small data structures, such as 
> vectors, matrices, or colors.
>
> (*) In my opinion.
>
> --------
>
> struct A { }
>
>  ---- Solution #1 ----
>
> // rvalues
> void foo(A a) {
> 	foo(a);
> }
>
> // lvalues
> void foo(ref A a) {
>
> }
>
> ----------------------------------
> Summarized: flexible, efficient but code bloat, more effort and 
> bug prone:
>
> void foo(A a) {
> 	writeln("call no ref");
> 	foo(a);
> }
>
> void foo(const ref A a) {
> 	writeln("call ref");
> }
>
> void main() {
> 	foo(A());
> }
>
> -> endless loop!
>
>  ---- Solution #2 ----
>
> // fuck it, copy lvalues and rvalues
> void foo(A a) {
>
> }
>
> ----------------------------------
> Summarized: flexible, no code bloat but inefficient -> 
> unnecessary copies
>
>  ---- Solution #3 ----
>
> // allow only lvalues
> void foo(ref A a) {
>
> }
>
> ----------------------------------
> Summarized: You have to make temporary values by yourself: 
> unhandy, ugly and code bloat
>
>  ---- Solution #4 ----
>
> // accept only pointers
> void foo(A* a) {
>
> }
>
> ----------------------------------
> Summarized: C Style, nullable and same problems as with 
> solutions #3.
>
>  ---- Solution #5 ----
>
> // Use classes
> class A { }
>
> // Works for lvalues and rvalues
> void foo(A a) {
>
> }
>
> ----------------------------------
> Summarized: flexible, efficient, no code bloat and same 
> creation (with static opCall) as structs. But: heap allocations 
> and nullable.

Honestly, I'd go with option 1. With a mixin template, it should 
be pretty to not mess up too hard.

Also, In regards to multi-args, I'd just bite the bullet, and 
make it so that if a single arg is rvalue, then all args are 
rvalue. Not perfect, but I think it is a good cost to gain ratio.

Here is a mixin template that *almost* does it:

//----
import std.stdio;
import std.conv;
import std.traits;

template rvalue(alias fun, string funs)
{
     private string ss()
     {
         //enum funs = fun.stringof; Don't know how to get 
function name :(
         enum Ret  = ReturnType!fun.stringof;
         alias Args = ParameterTypeTuple!fun;
         alias ParameterStorageClassTuple!fun pstc;
         enum names = [ParameterIdentifierTuple!fun];

         string s;
         s ~= Ret ~ " " ~ funs ~ "(";
         foreach(i, Type; Args[0 .. $])
         {
             if (pstc[i] == ParameterStorageClass.scope_) s ~= 
"scope ";
             if (pstc[i] == ParameterStorageClass.out_)   s ~= 
"out ";
             if (pstc[i] == ParameterStorageClass.lazy_)  s ~= 
"lazy ";
             //if (pstc[i] == ParameterStorageClass.ref_)  s ~= 
"ref "; //Commented: That's the whole point ;)
             s ~= Args[i].stringof ~ " ";
             s ~= names[i];
             if (i + 1 != Args.length) s ~= ", ";
         }
         s ~= ")";
         //TODO: print the FunctionAttribute
         s ~= "\n{\n    return " ~ funs ~ "(";
         if (Args.length)
         {
             s ~= names[0];
             foreach(i, Type; Args[1 .. $])
             {
                 s ~= ", " ~ names[i + 1];
             }
         }
         s ~= ");\n}\n";
         return s;
     }
     enum rvalue = ss();
}

void foo(ref int a, ref const int b, scope int c)
{
     writefln("%s %s %s", a, b, c);
}
mixin(rvalue!(foo, "foo"));

void main()
{
   foo(1, 2, 3);
   writeln(rvalue!(foo, "foo"));
}
//----
1 2 3
void foo(int a, const(int) b, scope int c)
{
     return foo(a, b, c);
}
//----

See? pretty nice. The only thing missing is actually getting the 
function name :/ I'm not sure how to do it, so I passed two 
arguments, but it should be doable with just 1 (worst case 
scenario, you pass just the string).

Also, I didn't code the FunctionAttribute part, but that's just 
because it's late and I want to sleep ;) It should be just about 
the same as with ParameterStorageClass.

You *could* further improve on this design, if you so felt like 
it, so that it generates all combination of ref/non ref 
parameters. That's more complicated. But doable.


More information about the Digitalmars-d-learn mailing list