digitalmars.D - template specialization for arrays
- J Arrizza (41/41) Oct 29 2011 I have a template that I'd like to have a specialization for arrays.
- Timon Gehr (18/59) Oct 29 2011 Fixed:
- Timon Gehr (17/91) Oct 29 2011 When using pattern matching, explicit template arguments are necessary.
- Timon Gehr (13/13) Oct 29 2011 This works too:
- J Arrizza (47/56) Oct 29 2011 The output is:
- Timon Gehr (22/79) Oct 29 2011 This works:
- Andrei Alexandrescu (4/25) Oct 29 2011 What's wrong with isStaticArray? Also, OP may want to look at
- J Arrizza (32/35) Oct 29 2011 Tried isStaticArray:
- Andrei Alexandrescu (10/17) Oct 29 2011 [snip]
- J Arrizza (66/71) Oct 30 2011 Andrei, I thought I had posted the entire program. Here it is again usin...
- Andrei Alexandrescu (7/37) Oct 30 2011 Thanks, sorry for having missed that.
- J Arrizza (35/37) Oct 30 2011 Yes, they are much simpler to use.
- Jonathan M Davis (7/10) Oct 30 2011 That page is talking about __traits (which is built into the compiler), ...
- Steven Schveighoffer (16/57) Oct 31 2011 The attraction of using specializations instead of constraints (aside fr...
- Jonathan M Davis (5/52) Oct 29 2011 Of course you do. A narrow string is a dynamic array, so it matches both...
- J Arrizza (2/9) Oct 29 2011 Yup, just tried it and works fine.
- J Arrizza (12/33) Oct 29 2011 Thank you Timon, I very much appreciate your (and others) help.
- Timon Gehr (27/61) Oct 30 2011 I cannot reproduce that behaviour. If I comment out the second and the
- J Arrizza (3/4) Oct 30 2011 $ dmd -v
I have a template that I'd like to have a specialization for arrays. Initiall I need it to work for byte arrays, but I'd like to make it eventually work for all arrays. The page http://d-programming-language.org/template says to use but when I try it, it doesn't quite work: template abc(T) { void abc(T parm1) { writeln("simpleparm: ", parm1); } } template abc(T: T[]) { void abc(T parm1) { writeln("array : ", parm1); } } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); } The output is: simpleparm: 1 simpleparm: str simpleparm: [1, 2] Which is not what I want, it needs to be the specialized template for arrays. Note, this doesn't work either: template abc(T: T[]) { void abc(T[] parm1) { writeln("array : ", parm1); } } John
Oct 29 2011
On 10/29/2011 05:24 PM, J Arrizza wrote:I have a template that I'd like to have a specialization for arrays. Initiall I need it to work for byte arrays, but I'd like to make it eventually work for all arrays. The page http://d-programming-language.org/template says to use but when I try it, it doesn't quite work: template abc(T) { void abc(T parm1) { writeln("simpleparm: ", parm1); } } template abc(T: T[]) { void abc(T parm1) { writeln("array : ", parm1); } } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); } The output is: simpleparm: 1 simpleparm: str simpleparm: [1, 2] Which is not what I want, it needs to be the specialized template for arrays. Note, this doesn't work either: template abc(T: T[]) { void abc(T[] parm1) { writeln("array : ", parm1); } } JohnFixed: template abc(T) { void abc(T parm1) { writeln("simpleparm: ", parm1); } } void abc(T:T[])(T[] parm1) { writeln("array : ", parm1); } void main(string[] args) { abc(1); abc!(typeof("str"))("str"); int[] arr = [1, 2]; abc!(int[])(arr); } The important thing to note is that when pattern matching on T[] is done, then T is the element type of the array, not the array type.
Oct 29 2011
On 10/29/2011 11:32 PM, Timon Gehr wrote:On 10/29/2011 05:24 PM, J Arrizza wrote:When using pattern matching, explicit template arguments are necessary. You probably don't want that, the following code does not need them: void abc(T)(T parm1) if(!isDynamicArray!T) { writeln("simpleparm: ", parm1); } void abc(T)(T parm1) if(isDynamicArray!T){ writeln("array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); }I have a template that I'd like to have a specialization for arrays. Initiall I need it to work for byte arrays, but I'd like to make it eventually work for all arrays. The page http://d-programming-language.org/template says to use but when I try it, it doesn't quite work: template abc(T) { void abc(T parm1) { writeln("simpleparm: ", parm1); } } template abc(T: T[]) { void abc(T parm1) { writeln("array : ", parm1); } } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); } The output is: simpleparm: 1 simpleparm: str simpleparm: [1, 2] Which is not what I want, it needs to be the specialized template for arrays. Note, this doesn't work either: template abc(T: T[]) { void abc(T[] parm1) { writeln("array : ", parm1); } } JohnFixed: template abc(T) { void abc(T parm1) { writeln("simpleparm: ", parm1); } } void abc(T:T[])(T[] parm1) { writeln("array : ", parm1); } void main(string[] args) { abc(1); abc!(typeof("str"))("str"); int[] arr = [1, 2]; abc!(int[])(arr); } The important thing to note is that when pattern matching on T[] is done, then T is the element type of the array, not the array type.
Oct 29 2011
This works too: void abc(T, U=void)(T parm1) { writeln("simpleparm: ", parm1); } void abc(T:U[],U)(T parm1) { writeln("array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); }
Oct 29 2011
When using pattern matching, explicit template arguments are necessary. You probably don't want that, the following code does not need them: void abc(T)(T parm1) if(!isDynamicArray!T) { writeln("simpleparm: ", parm1); } void abc(T)(T parm1) if(isDynamicArray!T){ writeln("array : ", parm1); }The output is: simpleparm: 1 dynamic array : str dynamic array : [1, 2] which sort of makes sense, but doesn't fit my app. It is possible to treat a string as an array of characters, but in my case I want to treat them as a single entity. The whole purpose of the array specialization is to search/manipulate/compare the individual elements of an array... except for strings. Ok, so I modified a little to take care of strings. But I also added another test for a static array and it's not playing nice anymore. void abc(T, U=void) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[], U) (T parm1) if (!isDynamicArray!T) //tried isStaticArray as well here { writeln("static array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; writeln("arr2 ", __traits(isStaticArray, arr2)); abc(arr2); } Output is: simpleparm: 1 string : str dynamic array : [1, 2] arr2 true simpleparm: [3, 4] // should be "static array: [3, 4]" John
Oct 29 2011
On 10/30/2011 12:52 AM, J Arrizza wrote:When using pattern matching, explicit template arguments are necessary. You probably don't want that, the following code does not need them: void abc(T)(T parm1) if(!isDynamicArray!T) { writeln("simpleparm: ", parm1); } void abc(T)(T parm1) if(isDynamicArray!T){ writeln("array : ", parm1); } The output is: simpleparm: 1 dynamic array : str dynamic array : [1, 2] which sort of makes sense, but doesn't fit my app. It is possible to treat a string as an array of characters, but in my case I want to treat them as a single entity. The whole purpose of the array specialization is to search/manipulate/compare the individual elements of an array... except for strings. Ok, so I modified a little to take care of strings. But I also added another test for a static array and it's not playing nice anymore. void abc(T, U=void) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[], U) (T parm1) if (!isDynamicArray!T) //tried isStaticArray as well here { writeln("static array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; writeln("arr2 ", __traits(isStaticArray, arr2)); abc(arr2); } Output is: simpleparm: 1 string : str dynamic array : [1, 2] arr2 true simpleparm: [3, 4] // should be "static array: [3, 4]" JohnThis works: void abc(T, U=void, size_t N=0) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[N], U, size_t N) (T parm1) { writeln("static array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; abc(arr2); }
Oct 29 2011
On 10/29/11 6:02 PM, Timon Gehr wrote:This works: void abc(T, U=void, size_t N=0) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[N], U, size_t N) (T parm1) { writeln("static array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; abc(arr2); }What's wrong with isStaticArray? Also, OP may want to look at isNarrowString. Andrei
Oct 29 2011
On Sat, Oct 29, 2011 at 4:14 PM, Andrei Alexandrescu < SeeWebsiteForEmail erdani.org> wrote:What's wrong with isStaticArray? Also, OP may want to look at isNarrowString. AndreiTried isStaticArray: void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[], U) (T parm1) if (isStaticArray!T) { writeln("static array : ", parm1); } It didn't match. The output was: simpleparm: 1 dynamic array : str dynamic array : [1, 2] simpleparm: [3, 4] isNarrowString isn't in the traits online doc. Looked it up in std/traits.d and I tried it: void abc(T) (T parm1) if (isNarrowString!T) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } and get compiler ambiguity for abc("str") between the two templates above. John
Oct 29 2011
On 10/29/11 6:44 PM, J Arrizza wrote:On Sat, Oct 29, 2011 at 4:14 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org <mailto:SeeWebsiteForEmail erdani.org>> wrote: What's wrong with isStaticArray? Also, OP may want to look at isNarrowString. Andrei Tried isStaticArray:[snip] I think you got quite a bit of advice for different approaches, which may get confusing. You should use either std.traits.isXxx systematically, or patterns systematically, but not both at the same time. Personally I prefer isXxx because they foster simple logic to decide what overloads should apply. Also, when posting, you may want to include complete short programs so others can try them quickly. Andrei
Oct 29 2011
You should use either std.traits.isXxx systematically, or patternsAndrei, I thought I had posted the entire program. Here it is again using only traits as you recommend: import std.stdio; import std.traits; void abc(T) (T parm1) if (isNarrowString!T || (!isStaticArray!T && !isDynamicArray!T)) { writeln("simpleparm: ", parm1); } void abc(T) (T parm1) if (!isNarrowString!T && (isDynamicArray!T || isStaticArray!T) ) { writeln("array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 = [3, 4]; abc(arr2); } And it does work, here's the output: simpleparm: 1 simpleparm: str array : [1, 2] array : [3, 4] Note my original intent was to differentiate between arrays and non-arrays only (lumping strings into non-array). As for using only patterns, I can't get the compiler to disambiguate between non-arrays and arrays: import std.stdio; import std.traits; void abc(T, U = void, size_t N = 0) (T parm1) //line 3 { writeln("simpleparm: ", parm1); } void abc(T: U[N], U = char, size_t N) (T parm1) { writeln("string : ", parm1); } void abc(T) (T parm1) { writeln("dynamic array : ", parm1); } void abc(T: U[N], U, size_t N) (T parm1) //line 15 { writeln("static array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 = [3, 4]; abc(arr2); //line 27 } Here's the compiler error: dtest.d(27): Error: template dtest.abc(T,U = void,ulong N = 0) abc(T,U = void,ulong N = 0) matches more than one template declaration, dtest.d(3):abc(T,U = void,ulong N = 0) and dtest.d(15):abc(T : U[N],U,ulong N)systematically, but not both at the same time. Personally I prefer isXxx because they foster simple logic to decide what overloads should apply.Also, when posting, you may want to include complete short programs so others can try them quickly.
Oct 30 2011
On 10/30/11 5:16 AM, J Arrizza wrote:You should use either std.traits.isXxx systematically, or patterns systematically, but not both at the same time. Personally I prefer isXxx because they foster simple logic to decide what overloads should apply. Also, when posting, you may want to include complete short programs so others can try them quickly. Andrei, I thought I had posted the entire program. Here it is again using only traits as you recommend: import std.stdio; import std.traits; void abc(T) (T parm1) if (isNarrowString!T || (!isStaticArray!T && !isDynamicArray!T)) { writeln("simpleparm: ", parm1); } void abc(T) (T parm1) if (!isNarrowString!T && (isDynamicArray!T || isStaticArray!T) ) { writeln("array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 = [3, 4]; abc(arr2); }Thanks, sorry for having missed that. The code as above is canonical. I think restricted templates are the way to go for most code. Pattern matching on types is rather arcane and should be let to a few advanced uses (such as implementing traits themselves). Andrei
Oct 30 2011
On Sun, Oct 30, 2011 at 7:36 AM, Andrei Alexandrescu < SeeWebsiteForEmail erdani.org> wrote:The code as above is canonical. I think restricted templates are the way to go for most code.Yes, they are much simpler to use. I went back to traits.d to see how isDynamicArray and isStaticArray were built mostly to figure out the patterns used for them. I found a couple more isArray!T and isSomeString which simplify and generalize the code just a little more: import std.stdio; import std.traits; void abc(T) (T parm1) if (isSomeString!T || !isArray!T) { writeln("simpleparm: ", parm1); } void abc(T) (T parm1) if (!isSomeString!T && isArray!T) { writeln("array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 = [3, 4]; abc(arr2); } Another one that looked promising is isIterable() for the array. All of this begs the question, where do I find the latest doc? Since these are not showing up in the online doc but are clearly in traits.d. http://d-programming-language.org/traits.html Thanks again for your help, John
Oct 30 2011
On Sunday, October 30, 2011 08:41:47 J Arrizza wrote:All of this begs the question, where do I find the latest doc? Since these are not showing up in the online doc but are clearly in traits.d. http://d-programming-language.org/traits.htmlThat page is talking about __traits (which is built into the compiler), not std.traits. For std.traits, you want http://www.d-programming-language.org/phobos/std_traits.html Depending on what you're doing, you may need both, but generally all you need is std.traits unless you're getting fancy. - Jonathan M Davis
Oct 30 2011
On Sun, 30 Oct 2011 10:36:26 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:On 10/30/11 5:16 AM, J Arrizza wrote:The attraction of using specializations instead of constraints (aside from the readability) is that specializations do not require modifying the non-specialized templates. For example: void abc(T)(T parm1) {...} void abc(T:int)(T parm1) {...} vs: void abc(T)(T parm1) if (!is(T : int)) {...} void abc(T)(T parm1) if (is(T: int)) {...} Note that the if(!is(T :int)) is required in the base case. This can quickly get out of hand if you have lots of specializations (see any phobos modules for lots of examples). It might be nice if constrained templates took precedence over non-constrained ones. -SteveYou should use either std.traits.isXxx systematically, or patterns systematically, but not both at the same time. Personally I prefer isXxx because they foster simple logic to decide what overloads should apply. Also, when posting, you may want to include complete short programs so others can try them quickly. Andrei, I thought I had posted the entire program. Here it is again using only traits as you recommend: import std.stdio; import std.traits; void abc(T) (T parm1) if (isNarrowString!T || (!isStaticArray!T && !isDynamicArray!T)) { writeln("simpleparm: ", parm1); } void abc(T) (T parm1) if (!isNarrowString!T && (isDynamicArray!T || isStaticArray!T) ) { writeln("array : ", parm1); } void main(string[] args) { writeln("v4"); abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 = [3, 4]; abc(arr2); }Thanks, sorry for having missed that. The code as above is canonical. I think restricted templates are the way to go for most code. Pattern matching on types is rather arcane and should be let to a few advanced uses (such as implementing traits themselves).
Oct 31 2011
On Saturday, October 29, 2011 16:44:16 J Arrizza wrote:On Sat, Oct 29, 2011 at 4:14 PM, Andrei Alexandrescu < SeeWebsiteForEmail erdani.org> wrote:Of course you do. A narrow string is a dynamic array, so it matches both. You need to change the second constraint to if(isDynamicArray!T && !isNarrowString!T), then narrow strings won't match both. - Jonathan M DavisWhat's wrong with isStaticArray? Also, OP may want to look at isNarrowString. AndreiTried isStaticArray: void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[], U) (T parm1) if (isStaticArray!T) { writeln("static array : ", parm1); } It didn't match. The output was: simpleparm: 1 dynamic array : str dynamic array : [1, 2] simpleparm: [3, 4] isNarrowString isn't in the traits online doc. Looked it up in std/traits.d and I tried it: void abc(T) (T parm1) if (isNarrowString!T) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } and get compiler ambiguity for abc("str") between the two templates above.
Oct 29 2011
On Sat, Oct 29, 2011 at 5:16 PM, Jonathan M Davis <jmdavisProg gmx.com>wrote:Yup, just tried it and works fine.and get compiler ambiguity for abc("str") between the two templatesabove. Of course you do. A narrow string is a dynamic array, so it matches both. You need to change the second constraint to if(isDynamicArray!T && !isNarrowString!T), then narrow strings won't match both. - Jonathan M Davis
Oct 29 2011
Thank you Timon, I very much appreciate your (and others) help. I will look all this up in the online docs and the book. There is still some very odd things in how these fit together. For example, if I comment out the last 3 function templates, I get all "simpleparms", which is expected. But if I add in the fourth, I get a compilation error saying the call to abc(arr2) is ambiguous. So even though the first one specifies "U = void" and "size_t N = 0", and the fourth specifies something very different, there is ambiguity between them. Adding in the third resolves the ambiguity between the first and fourth. John On Sat, Oct 29, 2011 at 4:02 PM, Timon Gehr <timon.gehr gmx.ch> wrote:This works: void abc(T, U=void, size_t N=0) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[N], U, size_t N) (T parm1) { writeln("static array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; abc(arr2); }
Oct 29 2011
On 10/30/2011 01:34 AM, J Arrizza wrote:Thank you Timon, I very much appreciate your (and others) help. I will look all this up in the online docs and the book. There is still some very odd things in how these fit together. For example, if I comment out the last 3 function templates, I get all "simpleparms", which is expected. But if I add in the fourth, I get a compilation error saying the call to abc(arr2) is ambiguous. So even though the first one specifies "U = void" and "size_t N = 0", and the fourth specifies something very different, there is ambiguity between them. Adding in the third resolves the ambiguity between the first and fourth. JohnI cannot reproduce that behaviour. If I comment out the second and the third, I get 3 "simpleparm"s and 1 "static array"On Sat, Oct 29, 2011 at 4:02 PM, Timon Gehr <timon.gehr gmx.ch <mailto:timon.gehr gmx.ch>> wrote: This works: void abc(T, U=void, size_t N=0) (T parm1) { writeln("simpleparm: ", parm1); } void abc(T: string) (T parm1) { writeln("string : ", parm1); } void abc(T:U[], U) (T parm1) if (isDynamicArray!T) { writeln("dynamic array : ", parm1); } void abc(T:U[N], U, size_t N) (T parm1) { writeln("static array : ", parm1); } void main(string[] args) { abc(1); abc("str"); int[] arr = [1, 2]; abc(arr); int[2] arr2 =[3, 4]; abc(arr2); }Whoops, just noticed that I accidentally left the if(isDynamicArray!T) in there. That is not necessary, if the pattern matches it will always evaluate to true. void abc(T, U=void, size_t N=0) (T parm1) { writeln("simpleparm: ", parm1); } //void abc(T: string) (T parm1) { // writeln("string : ", parm1); //} //void abc(T:U[], U) (T parm1){ // no constraint necessary // writeln("dynamic array : ", parm1); //} void abc(T:U[N], U, size_t N) (T parm1) { writeln("static array : ", parm1); } void main(string[] args) { abc(1); // simpleparm abc("str"); // simpleparm int[] arr = [1, 2]; abc(arr); // simpleparm int[2] arr2 =[3, 4]; abc(arr2); // static array } What compiler version are you using?
Oct 30 2011
On Sun, Oct 30, 2011 at 3:13 AM, Timon Gehr <timon.gehr gmx.ch> wrote:What compiler version are you using?$ dmd -v DMD64 D Compiler v2.055
Oct 30 2011