July 29, 2013
On Monday, 29 July 2013 at 17:28:57 UTC, Meta wrote:
> On Monday, 29 July 2013 at 17:22:50 UTC, JS wrote:
>> I'm not sure how named parameters would solve the original problem
>
> Your original use case:
>
> template t(T1..., T2...)
>
> ...
>
> t!(a, b, c; d, e, f);
>
> Becomes
>
> //Some weird hypothetical syntax
> template t(@name("T1") T1..., @name("T2") T2...)
> {
>     ...
> }
>
> t!(T1 = a, b, c, T2 = d, e, f);
>
>> but using a syntax like what I'm suggesting one can do stuff like
>>
>> ...
>
> I think these use cases would all work with named parameters.

I don't think that is very robust notation but if it is then it would work.

Using ';' makes it obvious the next group is starting. In your notation, it seems like there could be issues. What if T2 is a local variable, then is that an assignment? If there is no possible issues then I wouldn't mind having such a syntax... anything is better than nothing.

July 29, 2013
On Monday, 29 July 2013 at 17:35:09 UTC, JS wrote:
> I don't think that is very robust notation but if it is then it would work.
>
> Using ';' makes it obvious the next group is starting.

I think using f(..., name = ...) is pretty obvious, and possibly easier to spot in a list of commas than `;`.

> In your notation, it seems like there could be issues. What if T2 is a local variable, then is that an assignment? If there is no possible issues then I wouldn't mind having such a syntax... anything is better than nothing.

I don't think it would be an issue, as it would work the same way as local variables in functions that shadow those in an outer scope.

import std.stdio;

void main()
{
	int x = 2;
	int test1(int x, int y)
	{
		return x + y;
	}
	auto n = test1(0, 1);
	
	//Prints 1
	writeln(n);
}

As for templates, I think you currently can't define templates inside a function, so that wouldn't be an issue. As for using this notation in a template argument list, I believe it works the same way for templates.

alias T1 = int;

template t(T1)
{
	alias t = T1;
}

void main()
{
        //Prints "string"
	pragma(msg, t!string);
}

So the requisite variadic template:

alias T1 = TypeTuple!(int, string);

template t(@name("T1") T1..., @name("T2") T2...)
{
    alias t = T1;
}

void main()
{
    //Should print (double, char)
    pragma(msg, t!(T1 = double, char, T2 = bool));

    //Should print (int, string)
    pragma(msg, T1);
}
July 29, 2013
On Monday, 29 July 2013 at 17:52:41 UTC, Meta wrote:
>> In your notation, it seems like there could be issues. What if T2 is a local variable, then is that an assignment? If there is no possible issues then I wouldn't mind having such a syntax... anything is better than nothing.
>
> I don't think it would be an issue, as it would work the same way as local variables in functions that shadow those in an outer scope.
>
> ...

Actually, I think I misunderstood your meaning. You're right, this could be a problem. Currently:

import std.stdio;

void main()
{
	int x = 0;
	int test(int x, int y)
	{
		return x + y;
	}
        //Prints 2
	writeln(test(x = 1, 1));
        //Prints 1
	writeln(x);
}


So in a hypothetical situation where we now have named parameters:

import std.stdio;

void main()
{
    int x = 0;
    int test(@name("x") x, @name("y") y)
    {
        return x + y;
    }
    //Prints 3
    writeln(test(x = 1, y = 2));
    //What does this print?
    writeln(x);
}
July 29, 2013
On 07/29/13 17:03, bearophile wrote:
> errors += global.endGagging(oldGaggedErrors);
> 
> It's replaced with:
> if (global.endGagging(oldGaggedErrors))
>     errors = true;
> 
> Looking at that code it's easy to think about code like this, that is not currently supported:
> 
> errors ||= global.endGagging(oldGaggedErrors);
> 
> Is the "||=" operator useful?

Not really.

   errors |=!! global.endGagging(oldGaggedErrors);

artur
July 29, 2013
On 07/29/13 17:24, bearophile wrote:
> Maybe there is a way to allow that too:
> 
> 
> template Select(bool condition, T...) if (T.length == 2) {
>     static if (condition)
>         enum Select = T[0];
>     else
>         enum Select = T[1];
> }
> 
> void main() {
>     enum x = Select!(true, 10, 20);// error
>     static assert(x == 10);
>     int a = 1;
>     int b = 2;
>     alias y = Select!(true, a, b);
>     assert(y == 1);
>     alias T = Select!(true, int, long);
>     static assert(is(T == int));
> }
> 
> 
> How do you tell apart values from not values? :-)

   template Select(bool condition, T...) if (T.length == 2) {
       static if (__traits(compiles, function { alias _1 = T[0]; alias _2 = T[1]; }))
          alias Select = T[!condition];
       else
          enum Select = T[!condition];
   }

artur
July 29, 2013
On 07/29/13 22:43, Artur Skawina wrote:
> On 07/29/13 17:24, bearophile wrote:
>> Maybe there is a way to allow that too:
>>
>>
>> template Select(bool condition, T...) if (T.length == 2) {
>>     static if (condition)
>>         enum Select = T[0];
>>     else
>>         enum Select = T[1];
>> }
>>
>> void main() {
>>     enum x = Select!(true, 10, 20);// error
>>     static assert(x == 10);
>>     int a = 1;
>>     int b = 2;
>>     alias y = Select!(true, a, b);
>>     assert(y == 1);
>>     alias T = Select!(true, int, long);
>>     static assert(is(T == int));
>> }
>>
>>
>> How do you tell apart values from not values? :-)
> 
>    template Select(bool condition, T...) if (T.length == 2) {
>        static if (__traits(compiles, function { alias _1 = T[0]; alias _2 = T[1]; }))
>           alias Select = T[!condition];
>        else
>           enum Select = T[!condition];
>    }

Or even:

   template Select(bool condition, T...) if (T.length == 2) {
       static if (__traits(compiles, function { alias _ = T[!condition]; }))
          alias Select = T[!condition];
       else
          enum Select = T[!condition];
   }

but that's a bit /too much/ magic -- allowing

    alias y1 = Select!(true, b, int);
    assert(y1 == 2);
    alias y2 = Select!(false, b, int);
    assert(is(y2==int));

is "neat", but could be confusing...

artur
July 30, 2013
On Monday, 29 July 2013 at 15:02:13 UTC, Robert Clipsham wrote:
> On Monday, 29 July 2013 at 14:46:02 UTC, Robert Clipsham wrote:
>> You can achieve this like so:
>> ----
>> template Outer(T...) {
>>    template Inner(U...) {
>>        // Do something with T and U
>>    }
>> }
>> Outer!(a, b, c).Inner!(d, e, f);
>> ----
>>
>> You can see an example of it in action here (type tuple intersection):
>> https://github.com/mrmonday/misc/blob/master/misc/misc.d#L5
>>
>> Robert
>
> What would be more interesting would be to have the ability to
> have variadic variadics, so you could use something like:
> ----
> template Outer(T...) {
>      template Inner(U... ...) {
>          // Do something with T, U[0], U[1], U[2..$]
>      }
> }
> Outer!(a, b, c).Inner!(d, e, f).Inner!(g, h, i); // Etc
> ----
> Of course that raises the question of variadic variadic variadics
> and variadic variadic variadic variadics and so on, and my
> proposed syntax is already silly............

I don't think so, this seems similar:

It would be cool if we could nest templates to get grouping


template tIF(alias cond)
{
    template tIF(alias T...)
    {
        template tIF(alias F...)
	{
	    ....
	}
}

then do

tIF!(cond)!(t1,t2,t3)!(f1,..,fn)

which would allow for a natural grouping of variadics. The notation may seem silly but only because it is not common.

which could have a short hand notation of

tIF!(cond; t1, t2, t3; f1, ..., fn);

(this way, if you can't keep track of your ';'s then you can use the long form)

July 30, 2013
On Monday, 29 July 2013 at 14:53:10 UTC, monarch_dodra wrote:
> A simple "Group" struct will solve the problem without a second thought:
>
> struct Group(Args...)
> {
>     alias Ungroup = Args;
> }

That is actually a TypeTuple that does not auto-expand. May be even worth defining it as "alias Ungroup = TypeTuple!(Args)" to be more self-documenting at cost of some redundancy.

Also it does not need to be a struct, templates are not mandatory eponymous.

I think it is best solution for topic starter problem in terms of ROI and worth inclusion into Phobos.
July 30, 2013
On 7/30/13 12:36 AM, Dicebot wrote:
> On Monday, 29 July 2013 at 14:53:10 UTC, monarch_dodra wrote:
>> A simple "Group" struct will solve the problem without a second thought:
>>
>> struct Group(Args...)
>> {
>> alias Ungroup = Args;
>> }
>
> That is actually a TypeTuple that does not auto-expand. May be even
> worth defining it as "alias Ungroup = TypeTuple!(Args)" to be more
> self-documenting at cost of some redundancy.
>
> Also it does not need to be a struct, templates are not mandatory
> eponymous.
>
> I think it is best solution for topic starter problem in terms of ROI
> and worth inclusion into Phobos.

Agreed.

Andrei
August 10, 2013
On Monday, 29 July 2013 at 13:23:23 UTC, JS wrote:
> Sometimes it's nice to be able to have groups of variadic parameters:
>
> template t(T1..., T2...)
>
> ...
>
> t!(a, b, c; d, e, f);
>
> so that a,b,c are for T1 and d,e,f are for T2.
>
> This can be done by making a symbol and breaking up a single variadic but is messy.
>
> I doubt such a feature will ever get added but who knows...

I was initially unimpressed, but after some recent work I would really like this feature. I have been using
  struct Group(T...)
  {
      alias Ungroup = T;
  }
but, useful as it is, this feels like something that should have some sugar on it.

  template A(T0 ..., T1 ...)
  {
  // use T0 & T1
  }

  A!(int, long, double; Point, int)

is so much nicer than

  template A(T0, T1)
  if(isGroup!T0 && isGroup!T1)
  {
      alias t0 = T0.Ungroup;
      alias t1 = T1.Ungroup;

      //use t0 && t1
  }

  A!(Group!(int, long, double), Group!(Point, int))