digitalmars.D.learn - Problem with templates
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- BCS <ao pathlink.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- BCS <ao pathlink.com> Jul 07 2008
- Sean Reque <seanthenewt yahoo.com> Jul 07 2008
- Clemens Hofreither <clemens.hofreither gmx.net> Jul 07 2008
- "Jarrett Billingsley" <kb3ctd2 yahoo.com> Jul 07 2008
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...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?
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=12935
Jul 07 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjpg$j5$1 digitalmars.com...Jarrett Billingsley Wrote:"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?
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=12935
And I replied with corrections :)
Jul 07 2008
Jarrett Billingsley Wrote:"Sean Reque" <seanthenewt yahoo.com> wrote in message news:g4tjpg$j5$1 digitalmars.com...Jarrett Billingsley Wrote:"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?
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=12935
And I replied with corrections :)
I am sorry. I missed your corrections. It does work now. Thanks!
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?
[...]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,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?
[...]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.
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
Jul 07 2008
Reply to Sean,BCS Wrote: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?
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.
delegate, not a function pointer.
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
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.html
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. -Clemens
You'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" <kb3ctd2 yahoo.com> 