View mode: basic / threaded / horizontal-split · Log in · Help
January 10, 2012
Taking a function or delegate as argument.
If I want to have a method taking a callback function, I have to specify 
if it should take a function or delegate even if I don't really care. 
What's the best way to accept either? I cannot see any wrapper for 
something like this in std.typecons.


import std.stdio, std.traits;

void f(int i, void function(int) fn) {
    fn(i);
}

void d(int i, void delegate(int) dg) {
    dg(i);
}

// ugly..
void g(F)(int i, F callback) {
    static assert(isSomeFunction!F, "callback is not a function");
    static assert(__traits(compiles, { callback(i); }), "callback does 
not take int as a parameter");
    callback(i);
}

void fcb(int i) {
    writeln(i);
}

void main() {

    // Error: function t.f (int i, void function(int) fn) is not 
callable using argument types (int,void delegate(int))
    // f(1, (int i) { writeln(i); });
    f(2, &fcb);
    d(3, (int i) { writeln(i); });
    //Error: function t.d (int i, void delegate(int) dg) is not 
callable using argument types (int,void function(int))
    //d(4, &fcb);
    g(5, &fcb);
    g(6, (int i) { writeln(i); });
    //g(7, 7); // not a function
    //g(8, (string s) { }); // does not take int as arg
}
January 10, 2012
Re: Taking a function or delegate as argument.
On 1/10/2012 10:05 PM, simendsjo wrote:
> If I want to have a method taking a callback function, I have to specify
> if it should take a function or delegate even if I don't really care.
> What's the best way to accept either? I cannot see any wrapper for
> something like this in std.typecons.

The simple way:

void callback(int i, void delegate(int) dg)
{
    dg(i);
}

void callback(int i, void function(int) fn)
{
    void wrap(int j)
    {
        function(j);
    }
    callback(i, &wrap);
}
January 10, 2012
Re: Taking a function or delegate as argument.
On 1/10/2012 10:43 PM, Mike Parker wrote:
> On 1/10/2012 10:05 PM, simendsjo wrote:
>> If I want to have a method taking a callback function, I have to specify
>> if it should take a function or delegate even if I don't really care.
>> What's the best way to accept either? I cannot see any wrapper for
>> something like this in std.typecons.
>
> The simple way:
>
> void callback(int i, void delegate(int) dg)
> {
> dg(i);
> }
>
> void callback(int i, void function(int) fn)
> {
> void wrap(int j)
> {
> function(j);
> }
> callback(i, &wrap);
> }

And of course, wrap should be calling fn(j), not function(j)!
January 10, 2012
Re: Taking a function or delegate as argument.
On 10.01.2012 14:43, Mike Parker wrote:
> On 1/10/2012 10:05 PM, simendsjo wrote:
>> If I want to have a method taking a callback function, I have to specify
>> if it should take a function or delegate even if I don't really care.
>> What's the best way to accept either? I cannot see any wrapper for
>> something like this in std.typecons.
>
> The simple way:
>
> void callback(int i, void delegate(int) dg)
> {
> dg(i);
> }
>
> void callback(int i, void function(int) fn)
> {
> void wrap(int j)
> {
> function(j);
> }
> callback(i, &wrap);
> }

Yeah, but a bit tedious.. I found toDelegate: 
http://dlang.org/phobos/std_functional.html#toDelegate
January 10, 2012
Re: Taking a function or delegate as argument.
On 2012-01-10 14:48, simendsjo wrote:
> On 10.01.2012 14:43, Mike Parker wrote:
>> On 1/10/2012 10:05 PM, simendsjo wrote:
>>> If I want to have a method taking a callback function, I have to specify
>>> if it should take a function or delegate even if I don't really care.
>>> What's the best way to accept either? I cannot see any wrapper for
>>> something like this in std.typecons.
>>
>> The simple way:
>>
>> void callback(int i, void delegate(int) dg)
>> {
>> dg(i);
>> }
>>
>> void callback(int i, void function(int) fn)
>> {
>> void wrap(int j)
>> {
>> function(j);
>> }
>> callback(i, &wrap);
>> }
>
> Yeah, but a bit tedious.. I found toDelegate:
> http://dlang.org/phobos/std_functional.html#toDelegate

Or make it a template parameter and check if it's callable using 
std.traits.isCallable.

-- 
/Jacob Carlborg
January 10, 2012
Re: Taking a function or delegate as argument.
On 10.01.2012 14:43, Mike Parker wrote:
> On 1/10/2012 10:05 PM, simendsjo wrote:
>> If I want to have a method taking a callback function, I have to specify
>> if it should take a function or delegate even if I don't really care.
>> What's the best way to accept either? I cannot see any wrapper for
>> something like this in std.typecons.
>
> The simple way:
>
> void callback(int i, void delegate(int) dg)
> {
> dg(i);
> }
>
> void callback(int i, void function(int) fn)
> {
> void wrap(int j)
> {
> function(j);
> }
> callback(i, &wrap);
> }

I tried the following, but I get some error messages:

h(9, (int i) { writeln(i); });

t.d(46): Error: template t.h(F) if (isCompatibleFunction!(F,void 
function(int))) does not match any function template declaration
t.d(46): Error: template t.h(F) if (isCompatibleFunction!(F,void 
function(int))) cannot deduce template function from argument types 
!()(int,void delegate(int))


template isCompatibleFunction(Src, Dest) {
    static assert(isSomeFunction!Src, "Source is not a function");
    static assert(isSomeFunction!Dest, "Destination is not a function");
    enum bool isCompatibleFunction =
        is(ParameterTypeTuple!Src == ParameterTypeTuple!Dest) &&
        is(ParameterStorageClassTuple!Src == 
ParameterStorageClassTuple!Dest) &&
        is(ReturnType!Src == ReturnType!Dest);
}

void h(F)(int i, F callback) if(isCompatibleFunction!(F, void 
function(int))) {
    callback(i);
}
January 10, 2012
Re: Taking a function or delegate as argument.
On 10.01.2012 15:53, Jacob Carlborg wrote:
> On 2012-01-10 14:48, simendsjo wrote:
>> On 10.01.2012 14:43, Mike Parker wrote:
>>> On 1/10/2012 10:05 PM, simendsjo wrote:
>>>> If I want to have a method taking a callback function, I have to
>>>> specify
>>>> if it should take a function or delegate even if I don't really care.
>>>> What's the best way to accept either? I cannot see any wrapper for
>>>> something like this in std.typecons.
>>>
>>> The simple way:
>>>
>>> void callback(int i, void delegate(int) dg)
>>> {
>>> dg(i);
>>> }
>>>
>>> void callback(int i, void function(int) fn)
>>> {
>>> void wrap(int j)
>>> {
>>> function(j);
>>> }
>>> callback(i, &wrap);
>>> }
>>
>> Yeah, but a bit tedious.. I found toDelegate:
>> http://dlang.org/phobos/std_functional.html#toDelegate
>
> Or make it a template parameter and check if it's callable using
> std.traits.isCallable.
>

Like this?
void callback(F)(int i, F fn) if(isCallable!F) {
  fn(i);
}

.. but then the parameters wouldn't be documented.
January 10, 2012
Re: Taking a function or delegate as argument.
On 01/10/2012 06:53 AM, Jacob Carlborg wrote:
> On 2012-01-10 14:48, simendsjo wrote:
>> On 10.01.2012 14:43, Mike Parker wrote:
>>> On 1/10/2012 10:05 PM, simendsjo wrote:
>>>> If I want to have a method taking a callback function, I have to
>>>> specify
>>>> if it should take a function or delegate even if I don't really care.
>>>> What's the best way to accept either? I cannot see any wrapper for
>>>> something like this in std.typecons.
>>>
>>> The simple way:
>>>
>>> void callback(int i, void delegate(int) dg)
>>> {
>>> dg(i);
>>> }
>>>
>>> void callback(int i, void function(int) fn)
>>> {
>>> void wrap(int j)
>>> {
>>> function(j);
>>> }
>>> callback(i, &wrap);
>>> }
>>
>> Yeah, but a bit tedious.. I found toDelegate:
>> http://dlang.org/phobos/std_functional.html#toDelegate
>
> Or make it a template parameter and check if it's callable using
> std.traits.isCallable.
>
What's wrong with toDelegate ? Seems to be pretty handy.

//simple snip
import std.functional;

int main()
{
    int delegate( int i) dg;
    alias dg callback;
    callback = toDelegate(&test);
    writeln( callback( 12 ) );
    readln();

    return 0;
}

int test(int i) { return 30 +i;}
January 10, 2012
Re: Taking a function or delegate as argument.
On 2012-01-10 20:24, bls wrote:
> On 01/10/2012 06:53 AM, Jacob Carlborg wrote:
>> On 2012-01-10 14:48, simendsjo wrote:
>>> On 10.01.2012 14:43, Mike Parker wrote:
>>>> On 1/10/2012 10:05 PM, simendsjo wrote:
>>>>> If I want to have a method taking a callback function, I have to
>>>>> specify
>>>>> if it should take a function or delegate even if I don't really care.
>>>>> What's the best way to accept either? I cannot see any wrapper for
>>>>> something like this in std.typecons.
>>>>
>>>> The simple way:
>>>>
>>>> void callback(int i, void delegate(int) dg)
>>>> {
>>>> dg(i);
>>>> }
>>>>
>>>> void callback(int i, void function(int) fn)
>>>> {
>>>> void wrap(int j)
>>>> {
>>>> function(j);
>>>> }
>>>> callback(i, &wrap);
>>>> }
>>>
>>> Yeah, but a bit tedious.. I found toDelegate:
>>> http://dlang.org/phobos/std_functional.html#toDelegate
>>
>> Or make it a template parameter and check if it's callable using
>> std.traits.isCallable.
>>
> What's wrong with toDelegate ? Seems to be pretty handy.
>
> //simple snip
> import std.functional;
>
> int main()
> {
> int delegate( int i) dg;
> alias dg callback;
> callback = toDelegate(&test);
> writeln( callback( 12 ) );
> readln();
>
> return 0;
> }
>
> int test(int i) { return 30 +i;}

A template parameter with a template constraint will accept any callable 
type. Function pointer, delegate, struct/class overloading the call 
operator and so on.

-- 
/Jacob Carlborg
January 11, 2012
Re: Taking a function or delegate as argument.
On 10/01/2012 19:56, Jacob Carlborg wrote:
<snip>
> A template parameter with a template constraint will accept any callable type. Function
> pointer, delegate, struct/class overloading the call operator and so on.

Indeed, this is done in the C++ STL quite a lot.

The drawback is that templated methods lose their virtuality, because it cannot be known 
in advance on what types the template will be instantiated in order to populate the vtable.

FWIW my utility library includes a delegate wrapper:
http://pr.stewartsplace.org.uk/d/sutil/

(dgwrap works in both D1 and D2, though other bits of the library need updating to current D2)

Stewart.
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home