Thread overview
how to handle void arguments in generic programming ?
Nov 11, 2013
Timothee Cour
Nov 11, 2013
Dicebot
Nov 11, 2013
Timon Gehr
Nov 11, 2013
Dicebot
Nov 11, 2013
Timon Gehr
November 11, 2013
The code snippet below doesn't work. Is there a way to make it work?

import std.stdio;
void main(){
  writelnIfNonVoid(writeln("ok"));
}
void writelnIfNonVoid(T...)(T a){
  static if(T.length)
    writeln(a);
}


November 11, 2013
On Monday, 11 November 2013 at 03:52:16 UTC, Timothee Cour wrote:
> The code snippet below doesn't work. Is there a way to make it work?
>
> import std.stdio;
> void main(){
>   writelnIfNonVoid(writeln("ok"));
> }
> void writelnIfNonVoid(T...)(T a){
>   static if(T.length)
>     writeln(a);
> }

Considering "cannot have parameters of type void" error, I doubt it. Using lambda can do as workaround though (returning void is legal):

import std.stdio;
import std.traits;

void main()
{
	writelnIfNonVoid(() { writeln("ok"); });
}

void writelnIfNonVoid(T)(T f)
	if (isSomeFunction!T)
{	
	static if (!is(ReturnType!T == void))
		writeln(a);
}
November 11, 2013
On 11/11/2013 04:52 AM, Timothee Cour wrote:
> The code snippet below doesn't work. Is there a way to make it work?
>
> import std.stdio;
> void main(){
>    writelnIfNonVoid(writeln("ok"));
> }
> void writelnIfNonVoid(T...)(T a){
>    static if(T.length)
>      writeln(a);
> }


import std.stdio;
void main(){
    writelnIfNonVoid(writeln("ok"));
}
void writelnIfNonVoid(T...)(lazy T a){
    static if(T.length){
        static if(is(T[0]==void)) a[0];
        else write(a[0]);
        static if(T.length==1) writeln();
        else writelnIfNonVoid(a[1..$]);
    }
}

Or, if you care about evaluation order and locking stdout:

import std.stdio;

void main(){
    writelnIfNonVoid(writeln("ok"));
}
void writelnIfNonVoid(T...)(lazy T a){
    import std.range, std.algorithm, std.conv;
    mixin({
        string[] indices=iota(a.length).map!(i=>"a["~to!string(i)~"]").array~"cast(void)0";
        string r;
        foreach(i,t;T){
            if(is(t==void))
                indices[i+1]="("~indices[i]~","~indices[i+1]~")";
            else r~=indices[i]~",";
        }
        if(r.length) r="writeln("~r~");";
        return r~indices[$-1]~";";
    }());
}


November 11, 2013
On Monday, 11 November 2013 at 13:06:14 UTC, Timon Gehr wrote:
> void writelnIfNonVoid(T...)(lazy T a){

Whoa, one can apply attributes to variadic argument list? Yummy!
November 11, 2013
On 11/11/2013 02:06 PM, Timon Gehr wrote:
>
> Or, if you care about evaluation order and locking stdout:

This was a little too quick. It does not work too well since if the last parameter is of type void, the newline is emitted before the trailing arguments of type void are evaluated, which may not be exactly what you wanted.

The following should work, however DMD does not properly support the (exp,Seq!()) construct, so it won't compile in this case:


alias Seq(T...)=T;
void writelnIfNonVoid(T...)(lazy T a){
    import std.range, std.algorithm, std.conv;
    mixin({
        string[] indices=iota(a.length).map!(i=>"a["~to!string(i)~"]").array~"Seq!()";
        string r;
        foreach(i,t;T){
            if(is(t==void))
                indices[i+1]="("~indices[i]~","~indices[i+1]~")";
            else r~=indices[i]~",";
        }
        if(r.length) return "writeln("~r~indices[$-1]~");";
        return indices[$-1]!="Seq!()"?indices[$-1]~";":"";
    }());
}

This could be worked around as follows, but then you might get more postblit invocations than in the previous version:

import std.stdio;

void main(){
    writelnIfNonVoid("123",writeln("ok"));
}
void writelnIfNonVoid(T...)(lazy T a){
    import std.conv;
    static if(T.length) mixin({
        string r,args;
        foreach(i,t;T){
            if(!is(t==void)){
                r~="auto r_"~to!string(i)~"=";
                args~="r_"~to!string(i)~",";
            }
            r~="a["~to!string(i)~"];";
        }
        return r~"writeln("~args~");";
    }());
}

(Not sure what you intended the exact rules for emmiting a line feed character to be.)