digitalmars.D - Request for Comments: a "curry expression" Feature
- Russell Lewis (96/96) Oct 05 2007 I mentioned this in .announce, where the 1 response was positive...I
- =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= (5/9) Oct 05 2007 Yes please!
I mentioned this in .announce, where the 1 response was positive...I thought I'd post it here to see if I could draw more discussion (positive or negative, I'm interested in both sides). The idea is a "curry expression", which is an expression inside a delegate literal whose value is computed at the time when the delegate is created, and the computed value is then passed as a curried parameter to the delegate. (In D, currying is where you declare a hidden struct on the heap which carries within it some arguments to be passed to a delegate. When you call the delegate, the curry mechanism passes *both* the curried arguments and your call-time arguments (if any) to the underlying function. http://en.wikipedia.org/wiki/Currying) Here is a basic example: int delegate() foo(int i) { return delegate int() { return curry i; } } The above is syntax sugar for the much less readable: int delegate() foo(int i) { return Curry(i, delegate int(int temp) { return temp; }); } where Curry(...) is a template which curries one or more arguments into a delegate. The point here is that this mechanism allows you to "copy" the stack frame (or, at least, as much of the stack frame as you need) into a delegate which will still be runnable after the stack returns. LOTS MORE EXAMPLES: Interesting things happen if you curry pointers: void delegate(int) SetThisLater(int *ptr) { return delegate void(int i) { *(curry ptr) = i; }; } I don't see any reason why you couldn't have more complex expressions in a curry expression: real delegate(real) StrangeFunc(real r1) { // this calls SomeComplexFunc(r1) once (at delegate creation time) // and then curries the result return delegate real(real r2) { return r2+ curry SomeComplexFunc(r1); }; } real delegate(real) StrangeFunc2(real r1) { // this calls SomeComplexFunc each time that the delegate is called return delegate real(real r2) { return r2+ SomeComplexFunc(curry r1); }; } Sometimes, you want to keep a "running tally" of the results from many different calls to the same delegate. Typically, you would do this simply by updating a stack variable. But that doesn't work if you need to keep the delegate alive after the stack returns. You can do it this way: int delegate(int) RunningSum() { return delegate(int i) { // "new int" is run at delegate creation time. So each // time that you call this delegate, sum is set to the // *same* pointer to the *same* int on the heap. int *sum = curry new int; (*sum) += i; return *sum; }; } Of course, you can still access your stack variables, if you want. You can even access variables in some expressions, even if they were curried into the delegate in other places: void Repeat(int count, void delegate() callback) { for(int i=0; i<count; i++) callback(); } void MyFunc() { int i = 1; Repeat(10, delegate void() { // the "curry i" below always uses the curried value // the "i" below reads from the stack frame writefln("%d %d", curry i, i); // this modifies the variable in the stack frame i++; }; } The code above would print: 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 Thoughts?
Oct 05 2007
Russell Lewis wrote:int delegate() foo(int i) { return delegate int() { return curry i; } }Yes please! Though real closures would provide this functionality automatically this seams like a nice compromise that might be a lot easier to implement in the compiler.
Oct 05 2007