www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Is this a bug?

reply =?UTF-8?B?TcOhcmNpbw==?= Martins <marcioapm gmail.com> writes:
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
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
prev sibling parent reply =?UTF-8?B?TcOhcmNpbw==?= Martins <marcioapm gmail.com> writes:
On Monday, 15 October 2018 at 16:46:34 UTC, Steven Schveighoffer 
wrote:
 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);
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 :(
Oct 15 2018
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
parent reply =?UTF-8?B?TcOhcmNpbw==?= Martins <marcioapm gmail.com> writes:
On Tuesday, 16 October 2018 at 02:13:21 UTC, Ali Çehreli wrote:
 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
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.
Oct 16 2018
parent Kagamin <spam here.lot> writes:
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
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 10/15/18 4:36 PM, Márcio Martins wrote:
 On Monday, 15 October 2018 at 16:46:34 UTC, Steven Schveighoffer wrote:
 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);
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
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; } }
 
 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
parent =?UTF-8?B?TcOhcmNpbw==?= Martins <marcioapm gmail.com> writes:
On Tuesday, 16 October 2018 at 13:09:34 UTC, Steven Schveighoffer 
wrote:
 On 10/15/18 4:36 PM, Márcio Martins 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; } }
 [...]
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
Ahah! Template inception is exactly what I was looking for! Works great! Thanks for the solution and the explanation!
Oct 16 2018