digitalmars.D.learn - Problem with templates
- Sean Reque (12/12) Jul 07 2008 Could someone help me understand why this function doesn't work?
- Jarrett Billingsley (35/61) Jul 07 2008 "shortC" is not a type, it's just the compiler outputting the type of th...
- Sean Reque (14/54) Jul 07 2008 Heh, thanks :). I have been programming in Ruby and Perl a lot lately, w...
- Jarrett Billingsley (11/35) Jul 07 2008 One, you're still using "first" and "second" but you've changed the name...
- Sean Reque (27/33) Jul 07 2008 Take this example:
- Sean Reque (21/21) Jul 07 2008 I just tried a D2 version of the curry function and it actually didn't w...
- Sean Reque (19/19) Jul 07 2008 Never mind, I wrote the function wrong. This actually works. Alpha compi...
- Jarrett Billingsley (4/24) Jul 07 2008 Of course it works, plus is a delegate :)
- Jarrett Billingsley (4/11) Jul 07 2008 Right. You'll have to do it for every function either way.
- Sean Reque (3/21) Jul 07 2008 I don't know :). I wrote in this post what I tried:
- Jarrett Billingsley (3/29) Jul 07 2008 And I replied with corrections :)
- Sean Reque (2/37) Jul 07 2008 I am sorry. I missed your corrections. It does work now. Thanks!
- BCS (4/24) Jul 07 2008 taking the address of a (non static) nested functions generates a delega...
- Sean Reque (8/38) Jul 07 2008 I see. Any idea why this revised function still doesn't work?
- BCS (13/57) Jul 07 2008 I don't have time right now to dig out the context but... IFTI might jus...
- Sean Reque (10/10) Jul 07 2008 Thanks BCS. What you gave me was sufficient to make the function. I coul...
- Clemens Hofreither (3/25) Jul 07 2008 Have you tried using "function" instead of "delegate"? AFAIK, delegates ...
- Jarrett Billingsley (5/9) Jul 07 2008 You're right about that. Delegates can also refer to non-static nested
- Sean Reque (2/34) Jul 07 2008 Ohhhhh.. I thought you had to use the delegate keyword to make something...
- BCS (3/12) Jul 07 2008 Short test for delegate vs. fn ptr: If you can reference any non-static,...
Could someone help me understand why this function doesn't work? R delegate(T) my_compose(R, IR, IT, T...)(IR delegate(T) first, R delegate(IT) second) { return delegate(T args) { second(first(args)); }; } I attempt to invoke the function like this: my_compose(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); where SQLAllocHandle is a C function that returns a short and SQL is a function that accepts a short as its only parameter. I get the following error: test.d(35): template test.my_compose(R,IR,IT,T...) does not match any function template declaration test.d(35): template test.my_compose(R,IR,IT,T...) cannot deduce template function from argument types !()(shortC function(short, void*, void**),void function(short rc)) test.d(35): Error: function expected before (), not (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int I am using two separate template types, IR and IT, because according to the error message function 1 returns a shortC and function two accepts a short. I assume a shortC is implicitly convertible to a short :). I am guessing the shortC comes from the fact that SQLAllocHandle is an extern(C) function. I tried to model this function off of the Curry example in d 2.0 on this page: http://digitalmars.com/d/2.0/template.html. I am using version 2.015. I really don't understand how what I am doing is any different conceptually than this curry example, which works fine.
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tbqt$2g8k$1 digitalmars.com...Could someone help me understand why this function doesn't work? R delegate(T) my_compose(R, IR, IT, T...)(IR delegate(T) first, R delegate(IT) second) { return delegate(T args) { second(first(args)); }; } I attempt to invoke the function like this: my_compose(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); where SQLAllocHandle is a C function that returns a short and SQL is a function that accepts a short as its only parameter. I get the following error: test.d(35): template test.my_compose(R,IR,IT,T...) does not match any function template declaration test.d(35): template test.my_compose(R,IR,IT,T...) cannot deduce template function from argument types !()(shortC function(short, void*, void**),void function(short rc)) test.d(35): Error: function expected before (), not (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int I am using two separate template types, IR and IT, because according to the error message function 1 returns a shortC and function two accepts a short. I assume a shortC is implicitly convertible to a short :). I am guessing the shortC comes from the fact that SQLAllocHandle is an extern(C) function. I tried to model this function off of the Curry example in d 2.0 on this page: http://digitalmars.com/d/2.0/template.html. I am using version 2.015. I really don't understand how what I am doing is any different conceptually than this curry example, which works fine."shortC" is not a type, it's just the compiler outputting the type of the function stupidly. It probably should read something like "extern(C) short function(short, void*, void**)". Even if your template did work, unless you're using D2, it will fail spectacularly at runtime since you're returning a delegate, and when you try to call said delegate it will simply give garbage or crash the program as it is trying to access the 'first' and 'second' locals off the stack which no longer exist. I tried compiling your code just using some D functions and ran into two issues: 1. The delegate that you return doesn't return anything. It should be "return second(first(args));" but that's probably just a typo. 2. The compiler ICEs once that's fixed. If the T parameter is changed to a non-tuple, it "works" (but again, in D1 the resulting delegate is invalid and gives garbage). Another way to implement compose involves creating a static function, which will probably be a bit faster too. import tango.io.Stdout; import tango.core.Traits; ReturnTypeOf!(f2) compose(alias f1, alias f2)(ParameterTupleOf!(f1) p) { return f2(f1(p)); } void main(char[][] args) { int foo(double x) { return cast(int)x; } int bar(int x) { return x * x; } Stdout.formatln("{}", compose!(foo, bar)(4.5)); } This should also work with C functions, no problem. If you're using Phobos, you'd instead import std.traits, use "ReturnType" instead of "ReturnTypeOf", and "ParameterTypeTuple" instead of "ParameterTupleOf".
Jul 07 2008
Thanks for your response, Jarret.Even if your template did work, unless you're using D2, it will fail spectacularly at runtime since you're returning a delegate, and when you try to call said delegate it will simply give garbage or crash the program as it is trying to access the 'first' and 'second' locals off the stack which no longer exist.I am using D 2.0, so I should be getting full closure support. But I am not yet even getting past the compile stage.I tried compiling your code just using some D functions and ran into two issues: 1. The delegate that you return doesn't return anything. It should be "return second(first(args));" but that's probably just a typo.Heh, thanks :). I have been programming in Ruby and Perl a lot lately, where the return keyword isn't necessary.2. The compiler ICEs once that's fixed. If the T parameter is changed to a non-tuple, it "works" (but again, in D1 the resulting delegate is invalid and gives garbage). Another way to implement compose involves creating a static function, which will probably be a bit faster too. import tango.io.Stdout; import tango.core.Traits; ReturnTypeOf!(f2) compose(alias f1, alias f2)(ParameterTupleOf!(f1) p) { return f2(f1(p)); } void main(char[][] args) { int foo(double x) { return cast(int)x; } int bar(int x) { return x * x; } Stdout.formatln("{}", compose!(foo, bar)(4.5)); } This should also work with C functions, no problem. If you're using Phobos, you'd instead import std.traits, use "ReturnType" instead of "ReturnTypeOf", and "ParameterTypeTuple" instead of "ParameterTupleOf".I tried writing the compose function to return a static function. Here is the new function: ReturnType!(f2) my_compose2(alias f1, alias f2)(ParameterTypeTuple!(f1) args) { return second(first(args)); } I again try to compose the functions and invoke them, this time like so: my_compose2!(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); Again, I get this error message: test.d(41): template test.my_compose2(alias f1,alias f2) does not match any function template declaration test.d(41): template test.my_compose2(alias f1,alias f2) cannot deduce template function from argument types !(& SQLAllocHandle,& SQL)(const(short),const(void*),void**) I still am not sure why my original compose function didn't work, either. Someone else posted that I should try using function inputs, but I thought that D could implicitly convert function pointers to delegates. Perhaps I am doing something else wrong, or making an incorrect assumption? Also, creating a static function that returns a value isn't sufficient for what I need. Basically I want to be able to create D versions of every C ODBC call I need that will check the return values of these functions and throw an exception on error. I could do that manually for each function, but then I might as well be coding in C or C++ :).
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tg3j$2pta$1 digitalmars.com...I tried writing the compose function to return a static function. Here is the new function: ReturnType!(f2) my_compose2(alias f1, alias f2)(ParameterTypeTuple!(f1) args) { return second(first(args)); } I again try to compose the functions and invoke them, this time like so: my_compose2!(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); Again, I get this error message: test.d(41): template test.my_compose2(alias f1,alias f2) does not match any function template declaration test.d(41): template test.my_compose2(alias f1,alias f2) cannot deduce template function from argument types !(& SQLAllocHandle,& SQL)(const(short),const(void*),void**)One, you're still using "first" and "second" but you've changed the names to "f1" and "f2". Two, you don't use address-of when passing alias arguments to templates. Just use "my_compose2!(SQLAllocHandler, SQL)".I still am not sure why my original compose function didn't work, either. Someone else posted that I should try using function inputs, but I thought that D could implicitly convert function pointers to delegates.It can't. Delegates and functions currently have different calling conventions and the compiler cannot automatically convert one to the other. Was this just intuition or did you read that it would somewhere?Perhaps I am doing something else wrong, or making an incorrect assumption? Also, creating a static function that returns a value isn't sufficient for what I need. Basically I want to be able to create D versions of every C ODBC call I need that will check the return values of these functions and throw an exception on error. I could do that manually for each function, but then I might as well be coding in C or C++ :).Why can't this be done with a static function? Or rather, I'm not seeing how using a delegate makes what you want to do easier.
Jul 07 2008
It can't. Delegates and functions currently have different calling conventions and the compiler cannot automatically convert one to the other. Was this just intuition or did you read that it would somewhere?Take this example: R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) { struct Foo { typeof(dg) dg_m; typeof(arg) arg_m; R bar(U u) { return dg_m(arg_m, u); } } Foo* f = new Foo; f.dg_m = dg; f.arg_m = arg; return &f.bar; } void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); Notice how the function Curry accepts a delegate, but a function pointer is actually passed in. I have personally re-written this function to take advantage of D2 closures and it worked perfectly fine.Why can't this be done with a static function? Or rather, I'm not seeing how using a delegate makes what you want to do easier.You know, I think you are write and that a static function would work. I would just instantiate templates for every function I wanted to create a new version of. I don't think I quite understood how it worked at first. And if I really needed a delegate, I could easily wrap the invocation of a specific template instantation inside a delegate call and use that. Unfortunately, neither your compose or my compose is working for me right now :(.
Jul 07 2008
I just tried a D2 version of the curry function and it actually didn't work. I swore I wrote one before that worked. Maybe I should try it with an older D compiler. I wrote this code: import std.stdio; /* R is return type * A is first argument type * U is TypeTuple of rest of argument types */ R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) { return delegate(U args) { return dg(A, args); }; } void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); writefln("%d", plus_two(6, 8)); // prints 16 } The compiler returns this error: dmd2: glue.c:847: virtual unsigned int Type::totym(): Assertion `0' failed.
Jul 07 2008
Never mind, I wrote the function wrong. This actually works. Alpha compilers have terrible error messages sometimes! import std.stdio; /* R is return type * A is first argument type * U is TypeTuple of rest of argument types */ R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) { return delegate R(U args) { return dg(arg, args); }; } void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); writefln("%d", plus_two(6, 8)); // prints 16 }
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjei$31ci$1 digitalmars.com...Never mind, I wrote the function wrong. This actually works. Alpha compilers have terrible error messages sometimes! import std.stdio; /* R is return type * A is first argument type * U is TypeTuple of rest of argument types */ R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) { return delegate R(U args) { return dg(arg, args); }; } void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); writefln("%d", plus_two(6, 8)); // prints 16 }Of course it works, plus is a delegate :) Now put "static" in front of the declaration of plus and watch it fail.
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tibc$2v3q$1 digitalmars.com...You know, I think you are write and that a static function would work. I would just instantiate templates for every function I wanted to create a new version of. I don't think I quite understood how it worked at first. And if I really needed a delegate, I could easily wrap the invocation of a specific template instantation inside a delegate call and use that.Right. You'll have to do it for every function either way.Unfortunately, neither your compose or my compose is working for me right now :(.Why isn't my implementation working?
Jul 07 2008
Jarrett Billingsley Wrote:"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tibc$2v3q$1 digitalmars.com...I don't know :). I wrote in this post what I tried: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=12935You know, I think you are write and that a static function would work. I would just instantiate templates for every function I wanted to create a new version of. I don't think I quite understood how it worked at first. And if I really needed a delegate, I could easily wrap the invocation of a specific template instantation inside a delegate call and use that.Right. You'll have to do it for every function either way.Unfortunately, neither your compose or my compose is working for me right now :(.Why isn't my implementation working?
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjpg$j5$1 digitalmars.com...Jarrett Billingsley Wrote:And I replied with corrections :)"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tibc$2v3q$1 digitalmars.com...I don't know :). I wrote in this post what I tried: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=12935You know, I think you are write and that a static function would work. I would just instantiate templates for every function I wanted to create a new version of. I don't think I quite understood how it worked at first. And if I really needed a delegate, I could easily wrap the invocation of a specific template instantation inside a delegate call and use that.Right. You'll have to do it for every function either way.Unfortunately, neither your compose or my compose is working for me right now :(.Why isn't my implementation working?
Jul 07 2008
Jarrett Billingsley Wrote:"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjpg$j5$1 digitalmars.com...I am sorry. I missed your corrections. It does work now. Thanks!Jarrett Billingsley Wrote:And I replied with corrections :)"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tibc$2v3q$1 digitalmars.com...I don't know :). I wrote in this post what I tried: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=12935You know, I think you are write and that a static function would work. I would just instantiate templates for every function I wanted to create a new version of. I don't think I quite understood how it worked at first. And if I really needed a delegate, I could easily wrap the invocation of a specific template instantation inside a delegate call and use that.Right. You'll have to do it for every function either way.Unfortunately, neither your compose or my compose is working for me right now :(.Why isn't my implementation working?
Jul 07 2008
Reply to Sean,[...]It can't. Delegates and functions currently have different calling conventions and the compiler cannot automatically convert one to the other. Was this just intuition or did you read that it would somewhere?Take this example:void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); Notice how the function Curry accepts a delegate, but a function pointer is actually passed in. I have personally re-written this function to take advantage of D2 closures and it worked perfectly fine.taking the address of a (non static) nested functions generates a delegate, not a function pointer.
Jul 07 2008
BCS Wrote:Reply to Sean,I see. Any idea why this revised function still doesn't work? R delegate(T) my_compose(R, IR, IT, T...)(IR function(T) first, R function(IT) second) { return delegate(T args) { return second(first(args)); }; } test.d(40): template test.my_compose(R,IR,IT,T...) does not match any function template declaration test.d(40): template test.my_compose(R,IR,IT,T...) cannot deduce template function from argument types !()(shortC function(short, void*, void**),void function(short rc)) test.d(40): Error: function expected before (), not (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int[...]It can't. Delegates and functions currently have different calling conventions and the compiler cannot automatically convert one to the other. Was this just intuition or did you read that it would somewhere?Take this example:void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); Notice how the function Curry accepts a delegate, but a function pointer is actually passed in. I have personally re-written this function to take advantage of D2 closures and it worked perfectly fine.taking the address of a (non static) nested functions generates a delegate, not a function pointer.
Jul 07 2008
Reply to Sean,BCS Wrote:I don't have time right now to dig out the context but... IFTI might just not be up to it. you might try something like this ReturnTypeOf!(S) delegate(ArgsOf!(F)) my_compose(F, S)(F first, S second) { static assert(IsAFunctionType!(F)); // this might do better as a constraint static assert(IsAFunctionType!(S)); return ReturnTypeOf!(S) delegate(ArgsOf!(F) args) { return second(first(args)); }; } I'm sure you can find or write the used templates. http://www.digitalmars.com/d/2.0/phobos/std_traits.htmlReply to Sean,I see. Any idea why this revised function still doesn't work? R delegate(T) my_compose(R, IR, IT, T...)(IR function(T) first, R function(IT) second) { return delegate(T args) { return second(first(args)); }; } test.d(40): template test.my_compose(R,IR,IT,T...) does not match any function template declaration test.d(40): template test.my_compose(R,IR,IT,T...) cannot deduce template function from argument types !()(shortC function(short, void*, void**),void function(short rc)) test.d(40): Error: function expected before (), not (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int[...]It can't. Delegates and functions currently have different calling conventions and the compiler cannot automatically convert one to the other. Was this just intuition or did you read that it would somewhere?Take this example:void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); Notice how the function Curry accepts a delegate, but a function pointer is actually passed in. I have personally re-written this function to take advantage of D2 closures and it worked perfectly fine.taking the address of a (non static) nested functions generates a delegate, not a function pointer.
Jul 07 2008
Thanks BCS. What you gave me was sufficient to make the function. I could not find and did not take the time to right the function IsFunction, but here is the working function in phobos. ReturnType!(S) delegate(ParameterTypeTuple!(F)) my_compose(F, S)(F first, S second) { //no equivalent of IsAFunctionType in phobos //static assert(IsAFunctionType!(F)); // this might do better as a constraint //static assert(IsAFunctionType!(S)); return delegate ReturnType!(S)(ParameterTypeTuple!(F) args) { return second(first(args)); } ; } It's too bad that the using typesafe variadics didn't work, as that solution seems cleaner, but i am very happy to find at least one way to get it to work. Sean
Jul 07 2008
Sean Reque Wrote:Could someone help me understand why this function doesn't work? R delegate(T) my_compose(R, IR, IT, T...)(IR delegate(T) first, R delegate(IT) second) { return delegate(T args) { second(first(args)); }; } I attempt to invoke the function like this: my_compose(&SQLAllocHandle, &SQL)(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env); where SQLAllocHandle is a C function that returns a short and SQL is a function that accepts a short as its only parameter. I get the following error: test.d(35): template test.my_compose(R,IR,IT,T...) does not match any function template declaration test.d(35): template test.my_compose(R,IR,IT,T...) cannot deduce template function from argument types !()(shortC function(short, void*, void**),void function(short rc)) test.d(35): Error: function expected before (), not (my_compose(R,IR,IT,T...))((& SQLAllocHandle),(& SQL)) of type int I am using two separate template types, IR and IT, because according to the error message function 1 returns a shortC and function two accepts a short. I assume a shortC is implicitly convertible to a short :). I am guessing the shortC comes from the fact that SQLAllocHandle is an extern(C) function. I tried to model this function off of the Curry example in d 2.0 on this page: http://digitalmars.com/d/2.0/template.html. I am using version 2.015. I really don't understand how what I am doing is any different conceptually than this curry example, which works fine.Have you tried using "function" instead of "delegate"? AFAIK, delegates refer to object member functions, whereas functions are global functions. Since your functions come from C, they'd certainly be global functions. -Clemens
Jul 07 2008
"Clemens Hofreither" <clemens.hofreither gmx.net> wrote in message news:g4td0m$2iqm$1 digitalmars.com...Have you tried using "function" instead of "delegate"? AFAIK, delegates refer to object member functions, whereas functions are global functions. Since your functions come from C, they'd certainly be global functions. -ClemensYou're right about that. Delegates can also refer to non-static nested functions. Though this initial solution still suffers from the problem of returning a delegate.
Jul 07 2008
Jarrett Billingsley Wrote:"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjei$31ci$1 digitalmars.com...Ohhhhh.. I thought you had to use the delegate keyword to make something a delegate, or otherwise it was a function by default. Guess I need to read the docs more carefully.Never mind, I wrote the function wrong. This actually works. Alpha compilers have terrible error messages sometimes! import std.stdio; /* R is return type * A is first argument type * U is TypeTuple of rest of argument types */ R delegate(U) Curry(R, A, U...)(R delegate(A, U) dg, A arg) { return delegate R(U args) { return dg(arg, args); }; } void main() { int plus(int x, int y, int z) { return x + y + z; } auto plus_two = Curry(&plus, 2); writefln("%d", plus_two(6, 8)); // prints 16 }Of course it works, plus is a delegate :) Now put "static" in front of the declaration of plus and watch it fail.
Jul 07 2008
Reply to Sean,Short test for delegate vs. fn ptr: If you can reference any non-static, non-global, non-local values, it will be a delegate.Of course it works, plus is a delegate :) Now put "static" in front of the declaration of plus and watch it fail.Ohhhhh.. I thought you had to use the delegate keyword to make something a delegate, or otherwise it was a function by default. Guess I need to read the docs more carefully.
Jul 07 2008