digitalmars.D.learn - Is this a bug?
- =?UTF-8?B?TcOhcmNpbw==?= Martins (23/23) Oct 15 2018 import std.stdio;
- Steven Schveighoffer (8/37) Oct 15 2018 No, not a bug.
- Steven Schveighoffer (3/5) Oct 15 2018 Sorry, incx!(Test!uint, 1, 2, 3)(t)
- =?UTF-8?B?TcOhcmNpbw==?= Martins (14/42) Oct 15 2018 This doesn't seem to work, because:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (20/23) Oct 15 2018 For deduction to work, there must be function arguments. So, just add
- =?UTF-8?B?TcOhcmNpbw==?= Martins (46/71) Oct 16 2018 That's not exactly what I am trying to do.
- Kagamin (19/19) Oct 16 2018 You can simply group them:
- Steven Schveighoffer (19/60) Oct 16 2018 Hm... didn't realize that. It seems to me like an odd limitation, but I
- =?UTF-8?B?TcOhcmNpbw==?= Martins (5/27) Oct 16 2018 Ahah! Template inception is exactly what I was looking for! Works
import std.stdio; void incx(T, Args...)(ref T t) { ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); // works t.incx!(); // works incx(t); // works t.incx!(1, 2, 3); // what? incx(t, 1, 2, 3); // what? writeln(t.x); } test.d(16): Error: template test.incx cannot deduce function from argument types !(1, 2, 3)(Test!uint), candidates are: test.d(3): test.incx(T, Args...)(ref T t) test.d(17): Error: template test.incx cannot deduce function from argument types !()(Test!uint, int, int, int), candidates are: test.d(3): test.incx(T, Args...)(ref T t) Failed: ["/usr/bin/dmd", "-v", "-o-", "test.d", "-I."]
Oct 15 2018
On 10/15/18 12:40 PM, Márcio Martins wrote:import std.stdio; void incx(T, Args...)(ref T t) { ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); // works t.incx!(); // works incx(t); // works t.incx!(1, 2, 3); // what? incx(t, 1, 2, 3); // what? writeln(t.x); } test.d(16): Error: template test.incx cannot deduce function from argument types !(1, 2, 3)(Test!uint), candidates are: test.d(3): test.incx(T, Args...)(ref T t)No, not a bug. I suspect you want this? void incx(Args..., T)(ref T t);test.d(17): Error: template test.incx cannot deduce function from argument types !()(Test!uint, int, int, int), candidates are: test.d(3): test.incx(T, Args...)(ref T t) Failed: ["/usr/bin/dmd", "-v", "-o-", "test.d", "-I."]Did you mean incx!(T, 1, 2, 3)(t) ? Or with the updated incx I suggested: incx!(1, 2, 3)(t) -Steve
Oct 15 2018
On 10/15/18 12:46 PM, Steven Schveighoffer wrote:Did you mean incx!(T, 1, 2, 3)(t) ?Sorry, incx!(Test!uint, 1, 2, 3)(t) -Steve
Oct 15 2018
On Monday, 15 October 2018 at 16:46:34 UTC, Steven Schveighoffer wrote:On 10/15/18 12:40 PM, Márcio Martins wrote:This doesn't seem to work, because: test.d(3): Error: template `test.incx(Args..., T)(ref T t)` template tuple parameter must be last one Are you sure it's not a bug? It would be very un-intuitive otherwise, no? Considering that the declaration is legal, and that the template parameter deduction works when Args.length == 0, but stops working when Args.length > 0. There seems to be no way around it, except manually specifying the type, which is not only annoying. I was trying to use UFCS to emulate a method on a family of structs, but this makes it impossible :(import std.stdio; void incx(T, Args...)(ref T t) { ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); // works t.incx!(); // works incx(t); // works t.incx!(1, 2, 3); // what? incx(t, 1, 2, 3); // what? writeln(t.x); } test.d(16): Error: template test.incx cannot deduce function from argument types !(1, 2, 3)(Test!uint), candidates are: test.d(3): test.incx(T, Args...)(ref T t)No, not a bug. I suspect you want this? void incx(Args..., T)(ref T t);
Oct 15 2018
On 10/15/2018 01:36 PM, Márcio Martins wrote:Considering that the declaration is legal, and that the template parameter deduction works when Args.length == 0, but stops working when Args.length > 0.For deduction to work, there must be function arguments. So, just add Args to the function parameter list and all works: import std.stdio; void incx(T, Args...)(ref T t, Args) { // <-- Added Args ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); t.incx!(); incx(t); t.incx(1, 2, 3); // <-- Removed '!' incx(t, 1, 2, 3); writeln(t.x); } Ali
Oct 15 2018
On Tuesday, 16 October 2018 at 02:13:21 UTC, Ali Çehreli wrote:On 10/15/2018 01:36 PM, Márcio Martins wrote:That's not exactly what I am trying to do. Maybe I can share that - perhaps you guys know a better way that circumvents these: I am trying to have have a method that takes as arguments a key-value pair, where key is a string, and value is an alias to something callable. So I want to do things like: t.on!( "abc", { writeln("abc"); }, "cde", { writeln("cde"); } ); I want to be able to hash the keys at compile time, and have the callables not allocate at all. The problem is that if `on` is a method on the aggregate `t`, then I can't do this because i am passing local function literal do non global template. I am not sure why this is a limitation, I supposed I'd have to dig in the compiler code to find that out. It certainly is an unexpected limitation, though. So I tried to have the `on` be a global function, that has a first argument of type T, a template parameter, and then takes a compile-time alias sequence of the key-value pairs, as mentioned earlier. This mostly works, except that it can't deduce the first argument type, and forces me to write it up. The issue is that it's a `voldemort` type, and even if wasn't it would be a quite complex type to write, and I don't want my users to have to write typeof() statements. How can I best do this? I suppose I could do pass all of it as a function argument instead, and have the first argument be correctly deduced, but the performance characteristics will be massively different, as I can no longer process the strings at compile time, and the delegates passed as parameter are guaranteed to allocate. Help me understand if these are actual fundamental limitations, bugs, or just the current implementation. It's quite frustrating to invest a bunch of hours into a design that intuitively, IMO, should work, just to find out it doesn't work due to an arbitrary language limitation, and then spend time looking for an alternative, and again, hit some intuitive language limitation. If I understand the underlying limitation/implementation, I can avoid these frustrations in the future.Considering that the declaration is legal, and that thetemplateparameter deduction works when Args.length == 0, but stopsworking whenArgs.length > 0.For deduction to work, there must be function arguments. So, just add Args to the function parameter list and all works: import std.stdio; void incx(T, Args...)(ref T t, Args) { // <-- Added Args ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); t.incx!(); incx(t); t.incx(1, 2, 3); // <-- Removed '!' incx(t, 1, 2, 3); writeln(t.x); } Ali
Oct 16 2018
You can simply group them: t.on!( handlers!( "abc", { writeln("abc"); }, "cde", { writeln("cde"); } ) ); handlers!( "abc", { writeln("abc"); }, "cde", { writeln("cde"); } ).bind(t);
Oct 16 2018
On 10/15/18 4:36 PM, Márcio Martins wrote:On Monday, 15 October 2018 at 16:46:34 UTC, Steven Schveighoffer wrote:Hm... didn't realize that. It seems to me like an odd limitation, but I can see how it's ambiguous. The solution is to double-template: template incx(Args...) { void incx(T)(ref T t) { ++t.x; } }On 10/15/18 12:40 PM, Márcio Martins wrote:This doesn't seem to work, because: test.d(3): Error: template `test.incx(Args..., T)(ref T t)` template tuple parameter must be last oneimport std.stdio; void incx(T, Args...)(ref T t) { ++t.x; } static struct Test(T) { T x; } void main() { Test!uint t; t.incx(); // works t.incx!(); // works incx(t); // works t.incx!(1, 2, 3); // what? incx(t, 1, 2, 3); // what? writeln(t.x); } test.d(16): Error: template test.incx cannot deduce function from argument types !(1, 2, 3)(Test!uint), candidates are: test.d(3): test.incx(T, Args...)(ref T t)No, not a bug. I suspect you want this? void incx(Args..., T)(ref T t);Are you sure it's not a bug? It would be very un-intuitive otherwise, no? Considering that the declaration is legal, and that the template parameter deduction works when Args.length == 0, but stops working when Args.length > 0.Not a bug, because when you explicitly specify template parameters, they are specified in left-to-right order. You have incx(T, Args...)(ref T t) t.incx!(1, 2, 3); // 1 => T (error), 2 => Args[0], 3 => Args[1] incx(t, 1, 2, 3); // typeof(t) => T (uses IFTI), Args == empty tuple, // 1, 2, 3 => extra runtime parameters that don't match anything? -Steve
Oct 16 2018
On Tuesday, 16 October 2018 at 13:09:34 UTC, Steven Schveighoffer wrote:On 10/15/18 4:36 PM, Márcio Martins wrote:Ahah! Template inception is exactly what I was looking for! Works great! Thanks for the solution and the explanation![...]Hm... didn't realize that. It seems to me like an odd limitation, but I can see how it's ambiguous. The solution is to double-template: template incx(Args...) { void incx(T)(ref T t) { ++t.x; } }[...]Not a bug, because when you explicitly specify template parameters, they are specified in left-to-right order. You have incx(T, Args...)(ref T t) t.incx!(1, 2, 3); // 1 => T (error), 2 => Args[0], 3 => Args[1] incx(t, 1, 2, 3); // typeof(t) => T (uses IFTI), Args == empty tuple, // 1, 2, 3 => extra runtime parameters that don't match anything? -Steve
Oct 16 2018