Jump to page: 1 2
Thread overview
Problem with templates
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
Sean Reque
Jul 07, 2008
BCS
Jul 07, 2008
Sean Reque
Jul 07, 2008
BCS
Jul 07, 2008
Sean Reque
Jul 07, 2008
Clemens Hofreither
July 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.


July 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".


July 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
July 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.


July 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++ :).



July 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.


July 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 :(.

July 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.


July 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
}
July 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?


« First   ‹ Prev
1 2