www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why can't templates use tuples for for argument types?

reply BCS <ao pathlink.com> writes:
|template Types(A...)
|{
|  template Values(A a)
|  {
|  }
|}
|
|alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;
Jul 16 2007
next sibling parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
BCS wrote:

 |template Types(A...)
 |{
 |  template Values(A a)
 |  {
 |  }
 |}
 |
 |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;

Probably because the compiler does not unfold the tuple. I've filed a bug about instantiating an array literal from a tuple. It has a similar problem: alias Tuple!(1,2,3) a; int[] foo = [ a ]; // does not work, but int[] foo = [ a[0], a[1], a[2] ]; // does Here you can also do
 |template Types(A...)
 |{
 |  template Values(A[0] a, A[1] b, A[2] c)
 |  {
 |  }
 |}
 |
 |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;

Jul 16 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Jari-Matti Mäkelä,

 Probably because the compiler does not unfold the tuple. I've filed a
 bug about instantiating an array literal from a tuple. It has a
 similar problem:
 
 alias Tuple!(1,2,3) a;
 
 int[] foo = [ a ];  // does not work, but
 int[] foo = [ a[0], a[1], a[2] ]; // does

So you are saying it's a bug? In that case, what is the bug number so I can add some more comments?
Jul 16 2007
parent reply Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
BCS wrote:

 Reply to Jari-Matti Mäkelä,
 
 Probably because the compiler does not unfold the tuple. I've filed a
 bug about instantiating an array literal from a tuple. It has a
 similar problem:
 
 alias Tuple!(1,2,3) a;
 
 int[] foo = [ a ];  // does not work, but
 int[] foo = [ a[0], a[1], a[2] ]; // does

So you are saying it's a bug? In that case, what is the bug number so I can add some more comments?

I think the first class tuples -bug covers this too: http://d.puremagic.com/issues/show_bug.cgi?id=1293 If you feel it's worth a new bug report, please do as you wish. I have to admit the situation is a bit unorthogonal - for example these work too: alias Tuple(int,int) a; void foo(a b) {} void bar() { a b; } But template baz(a b) {} doesn't.
Jul 16 2007
parent BCS <ao pathlink.com> writes:
Reply to Jari-Matti Mäkelä,

 I think the first class tuples -bug covers this too:
 
 http://d.puremagic.com/issues/show_bug.cgi?id=1293
 
 If you feel it's worth a new bug report, please do as you wish.

I just added my comments to that bug
Jul 17 2007
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
BCS wrote:
 |template Types(A...)
 |{
 |  template Values(A a)
 |  {
 |  }
 |}
 |
 |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;

int [] is not an allowed as a template value parameter. Only char[], wchar[], dchar[], integers, and floating-point types can be template value parameters. (In C++, only integers are allowed).
Jul 17 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Don,

 int [] is not an allowed as a template value parameter. Only char[],
 wchar[], dchar[], integers, and floating-point types can be template
 value parameters. (In C++, only integers are allowed).
 

strange, this works |template Types(A...) |{ | template Values(B...) | { | } |} | |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob; And while I'm thinking about it; why isn't there something like a "one space tuple"? A few times, I have wanted a template that works just like a tuple taking template but where one or more of the spots must be filled and a keep separate from the rest. template Foo(A, B...) {} these should work Foo!(1, int); Foo!(int, 1); Foo!(Foo!(int, 1)); this shouldn't Foo!(); (alias dosen't work)
Jul 17 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <ao pathlink.com> wrote in message 
news:ce0a3343bf108c99670e3f3ff2c news.digitalmars.com...
 A few times, I have wanted a template that works just like a tuple taking 
 template but where one or more of the spots must be filled and a keep 
 separate from the rest.

 template Foo(A, B...) {}

 these should work

 Foo!(1, int);
 Foo!(int, 1);
 Foo!(Foo!(int, 1));

 this shouldn't

 Foo!();

template Foo(A...) { static assert(A.length >= 1, "Foo needs at least one parameter"); do something with A[0]; do something else with A[1 .. $]; }
Jul 17 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Jarrett,

 "BCS" <ao pathlink.com> wrote in message
 news:ce0a3343bf108c99670e3f3ff2c news.digitalmars.com...
 
 A few times, I have wanted a template that works just like a tuple
 taking template but where one or more of the spots must be filled and
 a keep separate from the rest.
 
 template Foo(A, B...) {}
 
 these should work
 
 Foo!(1, int);
 Foo!(int, 1);
 Foo!(Foo!(int, 1));
 this shouldn't
 
 Foo!();
 

{ static assert(A.length >= 1, "Foo needs at least one parameter"); do something with A[0]; do something else with A[1 .. $]; }

How did you hack my system!!!! I'm sure you copied that right off my hard drive }:-| <g> All joking aside, I keep running into that so often that I want a cleaner way to do it. I want the proper usage documented in the code, not the comments and the asserts. I want to be able to talk about things by name without having to make aliases. It's a minor point but...
Jul 17 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <ao pathlink.com> wrote in message 
news:ce0a3343bf268c99691d2e8b71a news.digitalmars.com...
 How did you hack my system!!!! I'm sure you copied that right off my hard 
 drive }:-|

 <g>
 All joking aside, I keep running into that so often that I want a cleaner 
 way to do it. I want the proper usage documented in the code, not the 
 comments and the asserts. I want to be able to talk about things by name 
 without having to make aliases. It's a minor point but...

The issue is that there's currently no way to specify that a template parameter can be 'anything'. T means it's a type, alias T means it's a symbol, and <sometype> T means it's a value. If you could specify that a parameter could take anything, this would be trivial. How about using .. - it means it's kind of like a tuple, but shorter ;) template Foo(A.., B...) { } Or, take a page from Erlang: template Foo(A | B...) { } In this case, A can be anything, and not just a type, because it's on the left of a bar. An issue with this, however, is that you can't have a type parameter.
Jul 17 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Jarrett,

 "BCS" <ao pathlink.com> wrote in message
 news:ce0a3343bf268c99691d2e8b71a news.digitalmars.com...
 
 How did you hack my system!!!! I'm sure you copied that right off my
 hard drive }:-|
 
 <g>
 All joking aside, I keep running into that so often that I want a
 cleaner
 way to do it. I want the proper usage documented in the code, not the
 comments and the asserts. I want to be able to talk about things by
 name
 without having to make aliases. It's a minor point but...

parameter can be 'anything'. T means it's a type, alias T means it's a symbol, and <sometype> T means it's a value. If you could specify that a parameter could take anything, this would be trivial. How about using .. - it means it's kind of like a tuple, but shorter ;) template Foo(A.., B...) { } Or, take a page from Erlang: template Foo(A | B...) { } In this case, A can be anything, and not just a type, because it's on the left of a bar. An issue with this, however, is that you can't have a type parameter.

I like the ".." my thought was allow tuples anywhere, but if they aren't at the end, they take one and only one thing. template Foo(A..., B...) However it seems a bit messy with the location sensitive semantics.
Jul 17 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jarrett Billingsley wrote:
 "BCS" <ao pathlink.com> wrote in message 
 news:ce0a3343bf268c99691d2e8b71a news.digitalmars.com...
 How did you hack my system!!!! I'm sure you copied that right off my hard 
 drive }:-|

 <g>
 All joking aside, I keep running into that so often that I want a cleaner 
 way to do it. I want the proper usage documented in the code, not the 
 comments and the asserts. I want to be able to talk about things by name 
 without having to make aliases. It's a minor point but...

The issue is that there's currently no way to specify that a template parameter can be 'anything'. T means it's a type, alias T means it's a symbol, and <sometype> T means it's a value. If you could specify that a parameter could take anything, this would be trivial. How about using .. - it means it's kind of like a tuple, but shorter ;) template Foo(A.., B...) { } Or, take a page from Erlang: template Foo(A | B...) { } In this case, A can be anything, and not just a type, because it's on the left of a bar. An issue with this, however, is that you can't have a type parameter.

Walter resoundingly rejected some other proposal that involved '..' on the grounds that '..' looks far too much like '...' to bleary eyes. So I think .. is out. --bb
Jul 17 2007
parent BCS <BCS pathlink.com> writes:
Bill Baxter wrote:
 Jarrett Billingsley wrote:
 
 "BCS" <ao pathlink.com> wrote in message 
 news:ce0a3343bf268c99691d2e8b71a news.digitalmars.com...

 How did you hack my system!!!! I'm sure you copied that right off my 
 hard drive }:-|

 <g>
 All joking aside, I keep running into that so often that I want a 
 cleaner way to do it. I want the proper usage documented in the code, 
 not the comments and the asserts. I want to be able to talk about 
 things by name without having to make aliases. It's a minor point but...

The issue is that there's currently no way to specify that a template parameter can be 'anything'. T means it's a type, alias T means it's a symbol, and <sometype> T means it's a value. If you could specify that a parameter could take anything, this would be trivial. How about using .. - it means it's kind of like a tuple, but shorter ;) template Foo(A.., B...) { } Or, take a page from Erlang: template Foo(A | B...) { } In this case, A can be anything, and not just a type, because it's on the left of a bar. An issue with this, however, is that you can't have a type parameter.

Walter resoundingly rejected some other proposal that involved '..' on the grounds that '..' looks far too much like '...' to bleary eyes. So I think .. is out. --bb

How about A[1]... or A...[1] This would be a tuple that must have exactly 1 item. Plainly this would also allow A[4]... , a tuple with 4 items and might also extend to A[3..5]... a tuple with 3,4 or 5 items. (or would that be 3 or 4 to match the slice semantics?) This last bit wouldn't mix with normal tuples though.
Jul 18 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
BCS wrote:
 Reply to Don,
 
 int [] is not an allowed as a template value parameter. Only char[],
 wchar[], dchar[], integers, and floating-point types can be template
 value parameters. (In C++, only integers are allowed).

strange, this works |template Types(A...) |{ | template Values(B...) | { | } |} | |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob; And while I'm thinking about it; why isn't there something like a "one space tuple"? A few times, I have wanted a template that works just like a tuple taking template but where one or more of the spots must be filled and a keep separate from the rest. template Foo(A, B...) {} these should work Foo!(1, int); Foo!(int, 1); Foo!(Foo!(int, 1)); this shouldn't Foo!(); (alias dosen't work)

Rather than proposing a bunch of new syntax, isn't the solution just to make those things work as expected? If you want at least one thing it seems perfectly reasonable to me to do: template Foo(A, B...) { alias Tuple!(A,B) ArgTuple; ... } if that doesn't work, then that's what needs to be fixed. I don't really understand the point of wanting to be able to specify a template argument that could be *anything* -- alias, value, or symbol. Other than a big static if, I can't see how you would be able to implement any functionality when it could be any one of those things. But I'm probably just being dense. --bb
Jul 18 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:f7m9k9$es4$1 digitalmars.com...
 Rather than proposing a bunch of new syntax, isn't the solution just to 
 make those things work as expected?  If you want at least one thing it 
 seems perfectly reasonable to me to do:

 template Foo(A, B...) {
    alias Tuple!(A,B) ArgTuple;
    ...
 }

Well the issue is that an identifier as a template parameter already has a well-defined meaning - it's a type parameter. Changing it to allow anything seems awfully scary, hence the suggestions for new syntax.
Jul 18 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jarrett Billingsley wrote:
 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
 news:f7m9k9$es4$1 digitalmars.com...
 Rather than proposing a bunch of new syntax, isn't the solution just to 
 make those things work as expected?  If you want at least one thing it 
 seems perfectly reasonable to me to do:

 template Foo(A, B...) {
    alias Tuple!(A,B) ArgTuple;
    ...
 }

Well the issue is that an identifier as a template parameter already has a well-defined meaning - it's a type parameter. Changing it to allow anything seems awfully scary, hence the suggestions for new syntax.

Yeh I meant for the A to be a type there. I guess I just don't understand the use case for BCS's original example: template Foo(A, B...) {} these should work Foo!(1, int); Foo!(int, 1); Foo!(Foo!(int, 1)); If you don't even know what kind of entity a thing is, there's not much you can do with it. Anyway, since it's been a basically a dialogue between you and BCS so far, something tells me you haven't hit a nerve with many folks. My guess is that most folks aren't clear what the motivating use case is. And probably Walter isn't going to be much interested in this either without good use case examples. --bb
Jul 18 2007
parent Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 Jarrett Billingsley wrote:
 "Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
 news:f7m9k9$es4$1 digitalmars.com...
 Rather than proposing a bunch of new syntax, isn't the solution just 
 to make those things work as expected?  If you want at least one 
 thing it seems perfectly reasonable to me to do:

 template Foo(A, B...) {
    alias Tuple!(A,B) ArgTuple;
    ...
 }

Well the issue is that an identifier as a template parameter already has a well-defined meaning - it's a type parameter. Changing it to allow anything seems awfully scary, hence the suggestions for new syntax.

Yeh I meant for the A to be a type there. I guess I just don't understand the use case for BCS's original example: template Foo(A, B...) {} these should work Foo!(1, int); Foo!(int, 1); Foo!(Foo!(int, 1)); If you don't even know what kind of entity a thing is, there's not much you can do with it. Anyway, since it's been a basically a dialogue between you and BCS so far, something tells me you haven't hit a nerve with many folks. My guess is that most folks aren't clear what the motivating use case is. And probably Walter isn't going to be much interested in this either without good use case examples.

Actually, I only saw this thread a few days ago (because I don't read d.learn as much as the main group), and I am surprised that so few people responded. To me, this is one part of a whole lot of issues with template parameters, which I hope will sometime be solved by a big reform. Otherwise, it will remain what seems today to be a collection of kludges. As far as I'm concerned, the problems are: 1. tuple parameters allow int[] (and double[] and double[][], etc) as value parameters; template value parameters don't 2. there's no equivalent to typesafe varargs: you can't say, "give me a type tuple" or "give me a tuple of aliases" or "give me a value tuple" -- you can only say "give me a tuple" and then do static asserts. I find this quite annoying because most of the time I know exactly which I want. 3. There's no easy way to specify "give me just one value parameter of any type." The closest you can get is template foo(T, T S) {...} but the instantiation requires: foo!(int, 5); 4. There's no way to specify what BCS mentioned: "give me just one parameter, of any kind". I haven't needed this yet, though. 5. You can't do proper nested tuples without a going through "compile-time structs". (when thinking about template parameters in the past, I've always found it difficult to distinguish between "type" as in int/char/etc, and the "type" of a template parameter as in value/alias/type. I think "kind" is a good word for the latter) I don't know what other people think of these problems, but they don't seem too hard to solve (mind you, I haven't worked out the details, so I could well be wrong). I would imagine setting up some sort of inheritance of template parameter kind, so that there's a base kind, "any", from which "value", "alias" and "type" inherit, and from the "value" kind, all of the regular D types also inherit. [Additionally, you solve problem 1 above by, well, solving it.]
Jul 19 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Bill,


 
 I don't really understand the point of wanting to be able to specify a
 template argument that could be *anything* -- alias, value, or symbol.
 Other than a big static if, I can't see how you would be able to
 implement any functionality when it could be any one of those things.
 
 But I'm probably just being dense.
 
 --bb
 

One thing that it would be useful for would be a tuple template that does something with any tuple type // take exactly 2 and return true if they are the same template IsSame(A..,B..){const bool IsSame = ...} // take 1 or more and remove all of the first from the rest template Remove(remove.., from...) { static if(from.length == 0) { alias from Remove; } else { staic if(IsSame!(remove, from[0])) { alias Remove!(remove,from[1..$]) Remove } else { alias T!(from[0], Remove!(remove,from[1..$])) Remove } } } this would work as: Remove!(1,4,5,6,7,1,2,3); // gives (4,5,6,7,2,3) Remove!(int, byte, short, int, long); // gives (byte, short, long)
Jul 19 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
BCS wrote:
 Reply to Bill,
 
 
 I don't really understand the point of wanting to be able to specify a
 template argument that could be *anything* -- alias, value, or symbol.
 Other than a big static if, I can't see how you would be able to
 implement any functionality when it could be any one of those things.

 But I'm probably just being dense.

 --bb

One thing that it would be useful for would be a tuple template that does something with any tuple type // take exactly 2 and return true if they are the same template IsSame(A..,B..){const bool IsSame = ...} // take 1 or more and remove all of the first from the rest template Remove(remove.., from...) { static if(from.length == 0) { alias from Remove; } else { staic if(IsSame!(remove, from[0])) { alias Remove!(remove,from[1..$]) Remove } else { alias T!(from[0], Remove!(remove,from[1..$])) Remove } } } this would work as: Remove!(1,4,5,6,7,1,2,3); // gives (4,5,6,7,2,3) Remove!(int, byte, short, int, long); // gives (byte, short, long)

Ok. So it's basically for writing functions that manipulate tuples themselves. I agree, it does make sense to be able to do that, in a Lisp-y completeness kind of way. You can write something like Remove!(1).from!(4,5,6,1,2,3,4) now. Then if the first tuple is empty you just don't remove anything (and you can additionally enhance it to remove any of N things from the list instead of just 1 thing). But still, tuples are the cons and cdr of template metaprogramming. There shouldn't be arbitrary restrictions on how you can manipulate them based on what's in the slots. As an aside, I think Walter's right about the dots. I misread your example as being two '..'s initially instead of one .. and one ... arg. I did just wake up though. :-) --bb
Jul 19 2007
parent BCS <ao pathlink.com> writes:
Reply to Bill,


 As an aside, I think Walter's right about the dots.  I misread your
 example as being two '..'s initially instead of one .. and one ...
 arg.
 I did just wake up though. :-)
 --bb
 

Ahh. The joys of hypothetical syntax!!
Jul 19 2007
prev sibling parent reply James Dennett <jdennett acm.org> writes:
Don Clugston wrote:
 BCS wrote:
 |template Types(A...)
 |{
 |  template Values(A a)
 |  {
 |  }
 |}
 |
 |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;

int [] is not an allowed as a template value parameter. Only char[], wchar[], dchar[], integers, and floating-point types can be template value parameters. (In C++, only integers are allowed).

Not true of C++. Pointers to objects with external linkage are also allowed (even if we assume "integers" includes booleans and values of enumeration types). (Allowing floating point types used to be a common extension in C++ but was removed after experience with it.) -- James
Jul 17 2007
parent Don Clugston <dac nospam.com.au> writes:
James Dennett wrote:
 Don Clugston wrote:
 BCS wrote:
 |template Types(A...)
 |{
 |  template Values(A a)
 |  {
 |  }
 |}
 |
 |alias Types!(int, bool, int[]).Values!(1,true,[1,2,3]) bob;

wchar[], dchar[], integers, and floating-point types can be template value parameters. (In C++, only integers are allowed).

Not true of C++. Pointers to objects with external linkage are also allowed

I would classify those as alias parameters, not value parameters. It's the name, not the value, which gets name mangled. (even if we assume "integers" includes
 booleans and values of enumeration types).

 
 (Allowing floating point types used to be a common extension
 in C++ but was removed after experience with it.)

Yes, I think I saw it in an early version of Borland C++. But I don't see how you can do it properly without clearly specifying the FP ABI.
 
 -- James

Jul 19 2007