digitalmars.D.learn - Non-consistent implicit function template specializations
- Rekel (32/32) Aug 17 2021 When using implicit function templates, identical specialization
- Mike Parker (7/28) Aug 17 2021 The error is in your code. Both of your `foo` templates are
- Rekel (3/6) Aug 17 2021 I keep managing to disappoint myself greatly... this is absurd,
- Mike Parker (13/15) Aug 17 2021 We do have a paid Issue/Pull-Request manager now (Razvan Nitu),
- Rekel (2/14) Aug 17 2021 That's great to hear :), I'll keep it in mind.
- Rekel (58/58) Aug 17 2021 As my post was not the actual cause of my issue (my apology for
- Steven Schveighoffer (11/45) Aug 17 2021 This is an invalid specification, what is U? Did you mean:
- Rekel (8/21) Aug 17 2021 Yes, sorry typo in the forum.
- Steven Schveighoffer (10/16) Aug 17 2021 According to my tests, it prefers the `T` version over the static array
- Rekel (14/24) Aug 18 2021 Oh my, that's weird... Not meant to bash but given all I've seen
- =?UTF-8?Q?Ali_=c3=87ehreli?= (28/30) Aug 17 2021 I don't have such problems because I am not smart enough to understand
- Rekel (7/13) Aug 18 2021 I tried looking into how isArray is defined. Like, does being
- Paul Backus (3/6) Aug 18 2021 Did you read the documentation?
- Rekel (2/8) Aug 18 2021 Ah it's specifically static & dynamic arrays, I see.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (20/23) Aug 18 2021 The definitions are in phobos/std/traits.d
When using implicit function templates, identical specialization yield different results. Example: ```d void foo(T)(){ writeln("1"); } void foo(T : T[])(){ writeln("1"); } void main(string[] args) { // Works TFoo!(int).foo(); // "1" TFoo!(double[]).foo(); // "2" foo!(int)(); // "1" foo!(double[])(); // "1" ! } ``` I'm fairly certain the last call _should_ yield "2", yet it does not. Should I submit a bugreport? And will that even help? There's even 'NEW' bugs from 2016 :'c --- Interestingly enough, it seems I've made a previous thread about this in January (https://forum.dlang.org/post/zudtiruaxdfdwcjennmr forum.dlang.org), though in it I state `TFoo!(uint[]) yields the array version`, which as can be seen from the example above, is not or no longer true. Sadly I'm having issues with template arguments more often (https://forum.dlang.org/post/xkgpheuhohbffzgdbqhb forum.dlang.org) And I sadly don't see any improvement to this happening any time in the future. Even bugs don't seem to get fixed in any timely manner (Not meant as an insult, just being realistic :/).
Aug 17 2021
On Tuesday, 17 August 2021 at 09:59:53 UTC, Rekel wrote:When using implicit function templates, identical specialization yield different results. Example: ```d void foo(T)(){ writeln("1"); } void foo(T : T[])(){ writeln("1"); } void main(string[] args) { // Works TFoo!(int).foo(); // "1" TFoo!(double[]).foo(); // "2" foo!(int)(); // "1" foo!(double[])(); // "1" ! } ``` I'm fairly certain the last call _should_ yield "2", yet it does not.The error is in your code. Both of your `foo` templates are implemented to print `"1"`. Change the second one to print "2" and you will see the desired output. At any rate, to specialize on arrays you should generally be using something like `T : U[], U`. Ditto for pointers: `T : U*, U`.
Aug 17 2021
On Tuesday, 17 August 2021 at 10:14:07 UTC, Mike Parker wrote:The error is in your code. Both of your `foo` templates are implemented to print `"1"`. Change the second one to print "2" and you will see the desired output.I keep managing to disappoint myself greatly... this is absurd, so sorry.
Aug 17 2021
On Tuesday, 17 August 2021 at 09:59:53 UTC, Rekel wrote:time in the future. Even bugs don't seem to get fixed in any timely manner (Not meant as an insult, just being realistic :/).We do have a paid Issue/Pull-Request manager now (Razvan Nitu), and he's prioritizing issues for strike teams composed of volunteers willing to fix them. If you find a specific bug that is a blocker or a major headache, make a post about it here in the forums. Sometimes, the reason a bug hasn't been fixed is simply that it hasn't caught the attention of the right person. With Razvan in place, it's more likely such issues will be resolved, or at least moved up on the priority list, if you let him know about them. A forum post is an easy way to do that while also bringing it to the attention of others who may be looking for something to work on.
Aug 17 2021
On Tuesday, 17 August 2021 at 10:21:39 UTC, Mike Parker wrote:We do have a paid Issue/Pull-Request manager now (Razvan Nitu), and he's prioritizing issues for strike teams composed of volunteers willing to fix them. If you find a specific bug that is a blocker or a major headache, make a post about it here in the forums. Sometimes, the reason a bug hasn't been fixed is simply that it hasn't caught the attention of the right person. With Razvan in place, it's more likely such issues will be resolved, or at least moved up on the priority list, if you let him know about them. A forum post is an easy way to do that while also bringing it to the attention of others who may be looking for something to work on.That's great to hear :), I'll keep it in mind.
Aug 17 2021
As my post was not the actual cause of my issue (my apology for the mistake), I think I have found the actual reason I'm currently having problems. This seems to be related to a (seeming, I might be wrong) inability to specialize over both 1d and 2d arrays separately. (If constraining the length to values.) This brings me to 2 questions. 1. How does one specialize a template for both 1d and 2d arrays at the same time? 2. Are there any plans to rework templates? like: - Making `template TFoo(T : T[])` illegal. This makes little sense to me however I look at it, and as several people have advised against it it's confusing it's in the docs. (21.4.1) - Changing the way priorities are set using specializations in general, to make them less pitfall-y. - Allow for 2+d length specification. At the moment `T[][L]` works while `T[L][L]` does not seem to. ```d void foo(T)(T a){...} void foo(T:U[L], uint L)(T a){...} void foo(T:U[L][L], uint L)(T a){...} // Never matched void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively) // Alternative workaround, very cluttery but with more control. void foo(T)(T a) if(!is(typeof(a[0]))&&!is(typeof(a[0][0]))) {...} void foo(T, uint L)(T[L] a) if(!is(typeof(a[0]))){...} void foo(T, uint L)(T[L][L] a) {...} // Still does not work. void foo(T, unit L(T[][L] a) {static foreach(i;0..L) assert(a[i].length==L); ...} // Will (generally) work but may include runtime checking & is generally much less preferrable. // Should work with void main(string[] args) { foo([[1],[2]]); foo([1,2]); foo(1); } ``` - Supporting specializations such as the following (from https://forum.dlang.org/post/kdgfwlydkgmwvzrieyek forum.dlang.org): ```d void foo(L, T, uint S)(L l, T[S] r){ writeln("foo"); } void bar(L, R:T[S], T, uint S)(L l, R r){ writeln("bar"); } void main(string[] args) { foo(1, [1,2,3,4]); // "foo" bar(1, [1,2,3,4]); // "cannot deduce function" } ``` I'm actually still not sure why this shouldn't work, but changing bar to foo isn't too difficult. (though it's more preferrable to work regardless, it currently feels like a pitfall) --- Not sure if I'm asking the right questions, hope it's not of nuisance. - Rekel
Aug 17 2021
On 8/17/21 10:20 AM, Rekel wrote:As my post was not the actual cause of my issue (my apology for the mistake), I think I have found the actual reason I'm currently having problems. This seems to be related to a (seeming, I might be wrong) inability to specialize over both 1d and 2d arrays separately. (If constraining the length to values.) This brings me to 2 questions. 1. How does one specialize a template for both 1d and 2d arrays at the same time? 2. Are there any plans to rework templates? like: - Making `template TFoo(T : T[])` illegal. This makes little sense to me however I look at it, and as several people have advised against it it's confusing it's in the docs. (21.4.1) - Changing the way priorities are set using specializations in general, to make them less pitfall-y. - Allow for 2+d length specification. At the moment `T[][L]` works while `T[L][L]` does not seem to.You should try out things individually to see if they at least work.```d void foo(T)(T a){...} void foo(T:U[L], uint L)(T a){...}This is an invalid specification, what is U? Did you mean: void foo(T: U[L], U, uint L)(T a) {...}void foo(T:U[L][L], uint L)(T a){...} // Never matchedApart from another missing U, this is only a SQUARE 2d-array (both dimensions the same), your example below only calls with a 1x2 array.void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively)I don't think you need this, and I had to comment it out, or the compiler wouldn't build.// Should work with void main(string[] args) { foo([[1],[2]]); foo([1,2]); foo(1); } ```All these are calling with array literals, which default to dynamic arrays, not static arrays. -Steve
Aug 17 2021
On Tuesday, 17 August 2021 at 16:24:38 UTC, Steven Schveighoffer wrote:Yes, sorry typo in the forum.void foo(T:U[L], uint L)(T a){...}This is an invalid specification, what is U? Did you mean:void foo(T: U[L], U, uint L)(T a) {...}Again, sorry a typo, calling with `[[1,2],[3,4]]`.void foo(T:U[L][L], uint L)(T a){...} // Never matchedApart from another missing U, this is only a SQUARE 2d-array (both dimensions the same), your example below only calls with a 1x2 array.That is correct, it's equivalent thus causes 2 matches.void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively)I don't think you need this, and I had to comment it out, or the compiler wouldn't build.All these are calling with array literals, which default to dynamic arrays, not static arrays.I realise that is their default, though in this scenario they should (I believe) be used as static arrays. (This works for me in any case)
Aug 17 2021
On 8/17/21 2:07 PM, Rekel wrote:On Tuesday, 17 August 2021 at 16:24:38 UTC, Steven Schveighoffer wrote:According to my tests, it prefers the `T` version over the static array version. Which leads me to believe that it prefers a dynamic array over a static one. In fact, if I comment out the `T` version, it doesn't compile. It literally will not pick that specialization, even if it can interpret the literal that way. which is really bizarre, since if you do it without specializations, but just spelling out all the template components (as in your alternative workaround), it WILL pick that one over a dynamic array one. -SteveAll these are calling with array literals, which default to dynamic arrays, not static arrays.I realise that is their default, though in this scenario they should (I believe) be used as static arrays. (This works for me in any case)
Aug 17 2021
On Tuesday, 17 August 2021 at 18:27:21 UTC, Steven Schveighoffer wrote:According to my tests, it prefers the `T` version over the static array version. Which leads me to believe that it prefers a dynamic array over a static one. In fact, if I comment out the `T` version, it doesn't compile. It literally will not pick that specialization, even if it can interpret the literal that way. which is really bizarre, since if you do it without specializations, but just spelling out all the template components (as in your alternative workaround), it WILL pick that one over a dynamic array one.Oh my, that's weird... Not meant to bash but given all I've seen of argument deduction & templates & specializations... I think the implementation needs some serious rework 😅 --- Interestingly enough my approach will not even work for 2d array literals. It will manage going to int[][2], but int[2][2] is one step too far. Which is a real bummer. :( That is, it won't figure it out itself, but when you call `foo(T, uintL)(T[L][L]...` using an explicit `foo!(int, 2)` it _will_ work. Even though it manages T[L] just fine. Meanwhile T[2][L] _and_ T[L][2] won't work when called with a 2x2 array literal.
Aug 18 2021
On 8/17/21 2:59 AM, Rekel wrote:I don't have such problems because I am not smart enough to understand that syntax so I don't use it. :) I use template constraints (which have other problems). import std.traits; import std.stdio; template TFoo(T) if (!isArray!T) { void foo(){ writeln("not array"); } } template TFoo(T) if (isArray!T) { void foo(){ writeln("array"); } } void main() { TFoo!(int).foo(); TFoo!(int[]).foo(); } If you want 2 dimensional arrays, then you can use import std.range; isArray!T && (isArray!(ElementType!T)) Ali
Aug 17 2021
On Tuesday, 17 August 2021 at 18:46:05 UTC, Ali Çehreli wrote:I don't have such problems because I am not smart enough to understand that syntax so I don't use it. :) I use template constraints (which have other problems).Yeah, they seem to be a bit more trustworthy to some extent.If you want 2 dimensional arrays, then you can use import std.range; isArray!T && (isArray!(ElementType!T))I tried looking into how isArray is defined. Like, does being able to index mean it's an array, or are these only static &/or dynamic arrays? Though I couldn't understand the sourcecode. Hence I just use(d) `is(typeof(variable[0]))` and `is(typeof(variable[0][0]))`.
Aug 18 2021
On Wednesday, 18 August 2021 at 11:10:49 UTC, Rekel wrote:I tried looking into how isArray is defined. Like, does being able to index mean it's an array, or are these only static &/or dynamic arrays?Did you read the documentation? https://phobos.dpldocs.info/std.traits.isArray.html
Aug 18 2021
On Wednesday, 18 August 2021 at 13:35:07 UTC, Paul Backus wrote:On Wednesday, 18 August 2021 at 11:10:49 UTC, Rekel wrote:Ah it's specifically static & dynamic arrays, I see.I tried looking into how isArray is defined. Like, does being able to index mean it's an array, or are these only static &/or dynamic arrays?Did you read the documentation? https://phobos.dpldocs.info/std.traits.isArray.html
Aug 18 2021
On 8/18/21 4:10 AM, Rekel wrote:The definitions are in phobos/std/traits.d enum bool isArray(T) = isStaticArray!T || isDynamicArray!T; isStaticArray uses the compiler's __traits feature: enum bool isStaticArray(T) = __traits(isStaticArray, T); isDynamicArray uses the is expression but apparently has some history: template isDynamicArray(T) { static if (is(T == U[], U)) enum bool isDynamicArray = true; else static if (is(T U == enum)) // BUG: isDynamicArray / isStaticArray considers enums // with appropriate base types as dynamic/static arrays // Retain old behaviour for now, see // https://github.com/dlang/phobos/pull/7574 enum bool isDynamicArray = isDynamicArray!U; else enum bool isDynamicArray = false; } AliisArray!T && (isArray!(ElementType!T))I tried looking into how isArray is defined. Like, does being able to index mean it's an array, or are these only static &/or dynamic arrays?
Aug 18 2021