www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with templates

reply Sean Reque <seanthenewt yahoo.com> writes:
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
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent reply Sean Reque <seanthenewt yahoo.com> writes:
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
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent reply Sean Reque <seanthenewt yahoo.com> writes:
 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
next sibling parent reply Sean Reque <seanthenewt yahoo.com> writes:
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
parent reply Sean Reque <seanthenewt yahoo.com> writes:
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
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent reply Sean Reque <seanthenewt yahoo.com> writes:
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
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent Sean Reque <seanthenewt yahoo.com> writes:
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
prev sibling parent reply BCS <ao pathlink.com> writes:
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
parent reply Sean Reque <seanthenewt yahoo.com> writes:
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?
 
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.
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
parent reply BCS <ao pathlink.com> writes:
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?
 
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.
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
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
parent Sean Reque <seanthenewt yahoo.com> writes:
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
prev sibling next sibling parent reply Clemens Hofreither <clemens.hofreither gmx.net> writes:
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
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
prev sibling parent reply Sean Reque <seanthenewt yahoo.com> writes:
Jarrett Billingsley Wrote:

 "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.
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
parent BCS <ao pathlink.com> writes:
Reply to Sean,


 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.
Short test for delegate vs. fn ptr: If you can reference any non-static, non-global, non-local values, it will be a delegate.
Jul 07 2008