www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - A library similar to boost::bind

reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Hey there :)

I've created a template lib similar to boost::bind 
(http://www.boost.org/libs/bind/bind.html)

Grab it here:
http://158.75.59.9/~h3/code/bind.rar




Basically, it allows the coder to create 'bound' functions, with some of 
their args fixed, but also other fancy stuff.


Examples:

void foo(int a, int b) {}

// create a function out of foo with the second argument fixed to 4
auto b1 = bind(&foo, Arg0, 4);
b1(3);	// calls foo(3, 4)

// create a function out of foo with reversed args
auto b2 = bind(&foo, Arg1, Arg0);
b2(1, 2);	// calls foo(2, 1)

// create a function out of foo with both args fixed
auto b3 = bind(&foo, 5, 6);
b3();	// calls foo(5, 6)


It can also be used for function compositing, like:

int bar(int a, int b) { return a + b; }

auto b4 = bind(&foo, bind(&bar, Arg0, Arg1), Arg2);
b4(1, 2, 3);	// calls foo(bar(1, 2), 3)

auto b5 = bind(&foo, bind(&bar, Arg0, Arg0), Arg0);
b5(1);	// calls foo(bar(1, 1), 1)


If a function is declared to take different types that are then bound to 
a single param type, automatic type negotiation is done:

void func(int a, float b) {}
auto b6 = bind(&func, Arg0, Arg0);
b6(123);	// ok, b6 expects an int

Basically, out of all types for wich Arg[n] is to be used, the one is 
found that can be casted to all other


An additional feature of the library is an ability to expand tuples, e.g.

Tuple!(int, float) func2() { return makeTuple(1, 2.2f); }
auto b7 = bind(&func, bind(&func2));
b7();	// calls func(1, 2.2f)

Although func expects two arguments and func2 returns just one, func2 
returns a Tuple composed of types that match 'func' so it's 
expanded/decomposed to allow such a nesting

The 'bind' function returns an object with an overloaded opCall method. 
You can grab a delegate from it by calling .ptr() instead.

More examples can be found in the archive


There's a problem with the library though. It only seems to work on the 
windows version of DMD. When compiled on linux, DMD segfaults without 
providing any reasonable error message :(
What could also be improved upon, are error messages in case when some 
types don't match

Anyway, all constructive feedback is welcome. If you have any feature 
suggestions or bug reports, I'd be glad to hear them


-- 
Tomasz Stachowiak  /+ a.k.a. h3r3tic +/
Jun 18 2006
parent reply Lutger <Lutger_member pathlink.com> writes:
I'm a little late, but thanks!!! I was hoping somebody would do this. It works
like a charm. 

I tried studying the source, and while it's a LOT better to follow than boost, I
discovered I don't understand metaprogramming at all (yet), unfortunatly.
Can I ask you, how can I use the Tuple type and what are it's features?
This much I figured out:

Tuple!(int,int) someTuple;
someTuple.val!(1) = 5;
assert(someTuple.val!(1) == 5);

In article <e74hrn$1eo5$1 digitaldaemon.com>, Tom S says...
Hey there :)

I've created a template lib similar to boost::bind 
(http://www.boost.org/libs/bind/bind.html)

Grab it here:
http://158.75.59.9/~h3/code/bind.rar




Basically, it allows the coder to create 'bound' functions, with some of 
their args fixed, but also other fancy stuff.


Examples:

void foo(int a, int b) {}

// create a function out of foo with the second argument fixed to 4
auto b1 = bind(&foo, Arg0, 4);
b1(3);	// calls foo(3, 4)

// create a function out of foo with reversed args
auto b2 = bind(&foo, Arg1, Arg0);
b2(1, 2);	// calls foo(2, 1)

// create a function out of foo with both args fixed
auto b3 = bind(&foo, 5, 6);
b3();	// calls foo(5, 6)


It can also be used for function compositing, like:

int bar(int a, int b) { return a + b; }

auto b4 = bind(&foo, bind(&bar, Arg0, Arg1), Arg2);
b4(1, 2, 3);	// calls foo(bar(1, 2), 3)

auto b5 = bind(&foo, bind(&bar, Arg0, Arg0), Arg0);
b5(1);	// calls foo(bar(1, 1), 1)


If a function is declared to take different types that are then bound to 
a single param type, automatic type negotiation is done:

void func(int a, float b) {}
auto b6 = bind(&func, Arg0, Arg0);
b6(123);	// ok, b6 expects an int

Basically, out of all types for wich Arg[n] is to be used, the one is 
found that can be casted to all other


An additional feature of the library is an ability to expand tuples, e.g.

Tuple!(int, float) func2() { return makeTuple(1, 2.2f); }
auto b7 = bind(&func, bind(&func2));
b7();	// calls func(1, 2.2f)

Although func expects two arguments and func2 returns just one, func2 
returns a Tuple composed of types that match 'func' so it's 
expanded/decomposed to allow such a nesting

The 'bind' function returns an object with an overloaded opCall method. 
You can grab a delegate from it by calling .ptr() instead.

More examples can be found in the archive


There's a problem with the library though. It only seems to work on the 
windows version of DMD. When compiled on linux, DMD segfaults without 
providing any reasonable error message :(
What could also be improved upon, are error messages in case when some 
types don't match

Anyway, all constructive feedback is welcome. If you have any feature 
suggestions or bug reports, I'd be glad to hear them


-- 
Tomasz Stachowiak  /+ a.k.a. h3r3tic +/
Jul 07 2006
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Lutger wrote:
 I'm a little late, but thanks!!! I was hoping somebody would do this. It works
 like a charm. 
 
 I tried studying the source, and while it's a LOT better to follow than boost,
I
 discovered I don't understand metaprogramming at all (yet), unfortunatly.
 Can I ask you, how can I use the Tuple type and what are it's features?
 This much I figured out:
 
 Tuple!(int,int) someTuple;
 someTuple.val!(1) = 5;
 assert(someTuple.val!(1) == 5);
Thanks for testing and kind words :) I've uploaded an updated version at the same address: http://158.75.59.9/~h3/code/bind.rar As for the Tuple's features, it's really pretty basic, but at the same time quite powerful and allowing for the creation of many interesting templates. I'll use an example to demonstrate its features: Tuple!(int, float) a; a.val!(0) = 5; a.val!(1) = 2.3f; // simple printing writefln(a.toString); // various insertion ops auto b = a.prepend!(char[])("foo"); writefln(b.toString); auto c = b.append!(double)(1.234567); writefln(c.toString); auto d = c.insertAfter!(1, int)(1234); writefln(d.toString); // .length property like in arrays writefln("d.length: ", d.length); // behaves like a struct auto e = d.insertBefore!(1, char[])("another string..."); auto f = e; f.val!(1) = "modified !"; writefln(e.toString); writefln(f.toString); // direct access to fields. the '.val' is an templated alias, not an accessor function f.val!(3) += 2; writefln(typeid(typeof(f.val!(3)))); writefln(f.toString); struct Test { int x; float y; double z; char w; } // no extra costs static assert(Test.sizeof == (Tuple!(int, float, double, char)).sizeof); // easy creation. // "".dup is used because we don't like static arrays. writefln(makeTuple(1, 2.2, 5.f, "foo".dup, 2+7i, "bar".dup).toString); // nest 'em as you like writefln(makeTuple(makeTuple(1, 2), makeTuple(3, 4)).toString); -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 07 2006
next sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Tom S wrote:
 Lutger wrote:
 
 I'm a little late, but thanks!!! I was hoping somebody would do this. 
 It works
 like a charm.
 I tried studying the source, and while it's a LOT better to follow 
 than boost, I
 discovered I don't understand metaprogramming at all (yet), unfortunatly.
 Can I ask you, how can I use the Tuple type and what are it's features?
 This much I figured out:

 Tuple!(int,int) someTuple;
 someTuple.val!(1) = 5;
 assert(someTuple.val!(1) == 5);
Thanks for testing and kind words :) I've uploaded an updated version at the same address: http://158.75.59.9/~h3/code/bind.rar As for the Tuple's features, it's really pretty basic, but at the same time quite powerful and allowing for the creation of many interesting templates. I'll use an example to demonstrate its features: Tuple!(int, float) a; a.val!(0) = 5; a.val!(1) = 2.3f; // simple printing writefln(a.toString); // various insertion ops auto b = a.prepend!(char[])("foo"); writefln(b.toString); auto c = b.append!(double)(1.234567); writefln(c.toString); auto d = c.insertAfter!(1, int)(1234); writefln(d.toString); // .length property like in arrays writefln("d.length: ", d.length); // behaves like a struct auto e = d.insertBefore!(1, char[])("another string..."); auto f = e; f.val!(1) = "modified !"; writefln(e.toString); writefln(f.toString); // direct access to fields. the '.val' is an templated alias, not an accessor function f.val!(3) += 2; writefln(typeid(typeof(f.val!(3)))); writefln(f.toString); struct Test { int x; float y; double z; char w; } // no extra costs static assert(Test.sizeof == (Tuple!(int, float, double, char)).sizeof); // easy creation. // "".dup is used because we don't like static arrays. writefln(makeTuple(1, 2.2, 5.f, "foo".dup, 2+7i, "bar".dup).toString); // nest 'em as you like writefln(makeTuple(makeTuple(1, 2), makeTuple(3, 4)).toString);
I've started to write something similar for Pyd, but yours seems more full-featured. One useful function of mine is a tuple_from_fn template, which derives a tuple type directly from a function type, e.g.: void func(int i, char[] s) { } void main() { tuple_from_fn!(typeof(&func)) f; static assert(is(typeof(f) == tuple!(int, char[]))); } The closest thing my tuples have to "bind" is a simple "apply_tuple_to_fn" function that calls the function with the tuple. The one question I have is: How well does it handle default function arguments? So far I've managed to support them pretty well in Pyd, and I don't want to break that. -- Kirk McDonald Pyd: Wrapping Python with D http://dsource.org/projects/pyd/wiki
Jul 07 2006
parent Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Kirk McDonald wrote:
 I've started to write something similar for Pyd, but yours seems more 
 full-featured. One useful function of mine is a tuple_from_fn template, 
 which derives a tuple type directly from a function type, e.g.:
 
 void func(int i, char[] s) { }
 
 void main() {
     tuple_from_fn!(typeof(&func)) f;
     static assert(is(typeof(f) == tuple!(int, char[])));
 }
 
 The closest thing my tuples have to "bind" is a simple 
 "apply_tuple_to_fn" function that calls the function with the tuple.
Ah, I've got it in the Bind module, called 'getFuncArgsTypes'. A simple apply function template is also in the meta package, in its own Apply.d file :)
 The one question I have is: How well does it handle default function 
 arguments? So far I've managed to support them pretty well in Pyd, and I 
 don't want to break that.
I'm afraid that currently it doesn't handle them at all, since it operates on func types, not aliases. Thanks for pointing it out though, I'll have to think about adding support for them :) -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 07 2006
prev sibling next sibling parent Lutger <Lutger_member pathlink.com> writes:
Oh joy, this is great! Imho something like this would be nice in Phobos.

The FuncMeta module in bind is very useful too. I even managed to make a map
function object thanks to this module, such as in the list comprehension thread.
It can take a delegate, function or function object (and thus a bound function).
I don't think I would have the patience to attempt this in C++...

In article <e8m0i6$se2$1 digitaldaemon.com>, Tom S says...
Lutger wrote:
 I'm a little late, but thanks!!! I was hoping somebody would do this. It works
 like a charm. 
 
 I tried studying the source, and while it's a LOT better to follow than boost,
I
 discovered I don't understand metaprogramming at all (yet), unfortunatly.
 Can I ask you, how can I use the Tuple type and what are it's features?
 This much I figured out:
 
 Tuple!(int,int) someTuple;
 someTuple.val!(1) = 5;
 assert(someTuple.val!(1) == 5);
Thanks for testing and kind words :) I've uploaded an updated version at the same address: http://158.75.59.9/~h3/code/bind.rar As for the Tuple's features, it's really pretty basic, but at the same time quite powerful and allowing for the creation of many interesting templates. I'll use an example to demonstrate its features: Tuple!(int, float) a; a.val!(0) = 5; a.val!(1) = 2.3f; // simple printing writefln(a.toString); // various insertion ops auto b = a.prepend!(char[])("foo"); writefln(b.toString); auto c = b.append!(double)(1.234567); writefln(c.toString); auto d = c.insertAfter!(1, int)(1234); writefln(d.toString); // .length property like in arrays writefln("d.length: ", d.length); // behaves like a struct auto e = d.insertBefore!(1, char[])("another string..."); auto f = e; f.val!(1) = "modified !"; writefln(e.toString); writefln(f.toString); // direct access to fields. the '.val' is an templated alias, not an accessor function f.val!(3) += 2; writefln(typeid(typeof(f.val!(3)))); writefln(f.toString); struct Test { int x; float y; double z; char w; } // no extra costs static assert(Test.sizeof == (Tuple!(int, float, double, char)).sizeof); // easy creation. // "".dup is used because we don't like static arrays. writefln(makeTuple(1, 2.2, 5.f, "foo".dup, 2+7i, "bar".dup).toString); // nest 'em as you like writefln(makeTuple(makeTuple(1, 2), makeTuple(3, 4)).toString); -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 07 2006
prev sibling parent Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Tom S wrote:
 Lutger wrote:
 I'm a little late, but thanks!!! I was hoping somebody would do this.
 It works
 like a charm.
 I tried studying the source, and while it's a LOT better to follow
 than boost, I
 discovered I don't understand metaprogramming at all (yet), unfortunatly.
 Can I ask you, how can I use the Tuple type and what are it's features?
 This much I figured out:

 Tuple!(int,int) someTuple;
 someTuple.val!(1) = 5;
 assert(someTuple.val!(1) == 5);
Thanks for testing and kind words :) I've uploaded an updated version at the same address: http://158.75.59.9/~h3/code/bind.rar
Wow! Great peace of code, I really learned a lot from it :) I also agree with Lutger, something like this should be in Phobos/Ares.
Jul 07 2006