Thread overview | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 29, 2013 Variadic grouping | ||||
---|---|---|---|---|
| ||||
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... |
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | JS:
> I doubt such a feature will ever get added but who knows...
It seems a cute idea, but why don't you show two or more very different use cases? (Asking for a feature without showing use cases is not so good.)
Bye,
bearophile
|
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Monday, 29 July 2013 at 13:30:58 UTC, bearophile wrote: > JS: > >> I doubt such a feature will ever get added but who knows... > > It seems a cute idea, but why don't you show two or more very different use cases? (Asking for a feature without showing use cases is not so good.) > > Bye, > bearophile The usefulness should be obvious and I seriously doubt if someone thinks it is not then any example I could give would convince them otherwise. It came up for me trying to write a ternary if to use. struct tVariadicSplit { } template tuple(args...) { alias tuple = args; } template tMin(alias a, alias b) { static if (a < b) alias tMin = a; else alias tMin = b; } template tIf(alias cond, args...) { enum sp = std.typetuple.staticIndexOf!(tVariadicSplit, args); static if (sp < 0) enum spp = args.length; else enum spp = sp; static if (cond) alias tIf = args[0..tMin!($, spp)]; else alias tIf = args[tMin!($,spp+1)..$]; } I have to use tVariadicSplit to split the grouping(sure I could reduce the symbol name size, which I have done). Being able to write this as template tIf(alias cond, tArgs..., fArgs...) { static if (cond) alias tIf = tArgs; else alias tIf = fArgs; } Would be much much more elegant. |
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | JS: > The usefulness should be obvious and I seriously doubt if someone thinks it is not then any example I could give would convince them otherwise. It's not obvious for me :-) Explaining the "obvious" is sometimes necessary. > It came up for me trying to write a ternary if to use. > > > struct tVariadicSplit { } > template tuple(args...) { alias tuple = args; } > template tMin(alias a, alias b) > { > static if (a < b) alias tMin = a; else alias tMin = b; > } > > template tIf(alias cond, args...) > { > enum sp = std.typetuple.staticIndexOf!(tVariadicSplit, args); > static if (sp < 0) enum spp = args.length; else enum spp = sp; > static if (cond) alias tIf = args[0..tMin!($, spp)]; else alias tIf = args[tMin!($,spp+1)..$]; > } (In your code I suggest to put a newline after each semicolon). This is one use case, to implement a static ternary operator with multiple arguments. (But having multiple arguments is not so common). A possible static ternary operator syntax: enum foo = ct_cond !? Foo!5 : Bar!6; But in my opinion the need for it is not strong enough, better to keep the language simpler. Do you have a second use case? Bye, bearophile |
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | > A possible static ternary operator syntax:
>
> enum foo = ct_cond !? Foo!5 : Bar!6;
>
> But in my opinion the need for it is not strong enough, better to keep the language simpler.
A static ternary operator is sometimes handy, this is working code:
import std.typetuple: TypeTuple;
template Iota(int n) {
static if (n <= 0)
alias TypeTuple!() Iota;
else
alias TypeTuple!(Iota!(n-1), n-1) Iota;
}
void main() {
int[3] a, b;
foreach (i; Iota!3)
a[i] = b[i];
}
With the recently introduced syntax for enum and templates you could assume this works:
enum Iota(int n) = (n <= 0) ?
TypeTuple!() :
TypeTuple!(Iota!(n-1), n-1);
But that's a regular ternary operator, so despite only one branch is computed, both are verified for type, because they have to return the same type, so it gives:
Error: template instance test.Iota!-497 recursive expansion
A static ternary operator is allowed to return two different types, so no type is computed for the other branch, and this works:
enum Iota(int n) = (n <= 0) !?
TypeTuple!() :
TypeTuple!(Iota!(n-1), n-1);
Bye,
bearophile
|
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Monday, 29 July 2013 at 13:59:54 UTC, bearophile wrote: > JS: > >> The usefulness should be obvious and I seriously doubt if someone thinks it is not then any example I could give would convince them otherwise. > > It's not obvious for me :-) Explaining the "obvious" is sometimes necessary. > > >> It came up for me trying to write a ternary if to use. >> >> >> struct tVariadicSplit { } >> template tuple(args...) { alias tuple = args; } >> template tMin(alias a, alias b) >> { >> static if (a < b) alias tMin = a; else alias tMin = b; >> } >> >> template tIf(alias cond, args...) >> { >> enum sp = std.typetuple.staticIndexOf!(tVariadicSplit, args); >> static if (sp < 0) enum spp = args.length; else enum spp = sp; >> static if (cond) alias tIf = args[0..tMin!($, spp)]; else alias tIf = args[tMin!($,spp+1)..$]; >> } > > (In your code I suggest to put a newline after each semicolon). > > This is one use case, to implement a static ternary operator with multiple arguments. (But having multiple arguments is not so common). > > A possible static ternary operator syntax: > > enum foo = ct_cond !? Foo!5 : Bar!6; > I suggested that a while back. > But in my opinion the need for it is not strong enough, better to keep the language simpler. > Possibly because it doesn't exist? The problem is that when working with recursion on variadic parameters you have to deal with code like t!(args[0], args[1..$]) Sometimes you only want to return the last half of the args IF something is true, e.g., t!(args[0], tIf!(cond, args[1..$-2] else ";")); or whatever. The problem being that args is a tuple and you can't distinguish between what you want to return as true and what you want to return as false. To get around this you either have to create a split manually OR write static if's that create a lot of redundant code. > Do you have a second use case? > Then a third? The fact whether there is a use case or not, or whether I have one or not should be irrelevant. The issue should stand on it's own. Having some easily way to use multiple variadic parameters is either useful or not. If it is and not hard to implement then it should be implemented. People can't use something if it doesn't exist... and will find ways around the real problem. I think with a little work you could come up with many more and better use cases than I could. They all will related to a sort of this or that scenario though because else why would one need to split up the arguments in the first place if there was no need to distinguish the group. Join!(Strings...; Delims...) could Join the strings with their Delims. Map!(Objects...; Funcs...) Could be an easy way to apply functions to objects. most of these could be done by using a pair of values though but would be easier to use multiple variadics. Split!(Strings...; Splits...) could split each strings with all the split possibilities. e.g. Split!("abcdefg", "abc"; "b", "c") will split each string using each split. returns (["a", "defg"], ["a"]) Anyways, If you don't build it they won't come... |
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | On Monday, 29 July 2013 at 14:21:45 UTC, JS wrote:
> Then a third? The fact whether there is a use case or not, or whether I have one or not should be irrelevant. The issue should stand on it's own. Having some easily way to use multiple variadic parameters is either useful or not.
There are a mind-boggling large number of things that are useful, but that's not the criteria for adding something to a programming language.
A new feature has to be *sufficiently* useful to justify the increased complexity of the language and it's implementations (plus not clashing badly with other features). Example use cases are a useful way of demonstrating just how useful a feature can be.
|
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | 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... 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 |
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Monday, 29 July 2013 at 14:34:13 UTC, John Colvin wrote:
> On Monday, 29 July 2013 at 14:21:45 UTC, JS wrote:
>> Then a third? The fact whether there is a use case or not, or whether I have one or not should be irrelevant. The issue should stand on it's own. Having some easily way to use multiple variadic parameters is either useful or not.
>
> There are a mind-boggling large number of things that are useful, but that's not the criteria for adding something to a programming language.
>
> A new feature has to be *sufficiently* useful to justify the increased complexity of the language and it's implementations (plus not clashing badly with other features). Example use cases are a useful way of demonstrating just how useful a feature can be.
The need for "grouping variadics" creeps up every now and then, and it *would* be useful to provide support for it. It may seem like there isn't really a need, but it's not like a lot of people do meta programming with recursive variadics. But for those that *do* the requirement is obvious.
That said, it is *far* from requiring a language change.
A simple "Group" struct will solve the problem without a second thought:
struct Group(Args...)
{
alias Ungroup = Args;
}
So, if we take into account that phobos already has a static if for types (called select), it can become:
//----
void main()
{
enum a = false;
alias K = Select!(a, Group!(int, 1), Group!(double, 2)).Ungroup;
}
//----
See? There's no need to make such a fuss about this.
"Group", contrary to Tuple, is not meant to ever be instanciated. This makes it better in this scenario, as "Tuple!5" will not compile (how do you construct an instance of type "5")? Another advantage is that "Group" is an explicit type, which means you can for a template that doesn't have "alias" parameters to accpet values. EG:
Select!(cond, 1, 2);// This doesn't compile
Select!(a, Group!(1), Group!(2)).Ungroup; //But this does :)
It's a bit hackish, but it saves your butt.
The "issue" (I think) is that we don't have "Group" in phobos, forcing our users (eg. JS), to re-invent and re-write the wheel, over and over again, which is not great.
Placing this right under TypeTuple in std.typetuple seems ideal? Should I submit a pull/ER ?
|
July 29, 2013 Re: Variadic grouping | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Clipsham | 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............
|
Copyright © 1999-2021 by the D Language Foundation