www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - D doesn't have real closures

reply Brad Anderson <brad dsource.org> writes:
http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/

Please digg and reddit.

BA
Sep 11 2007
next sibling parent reply 0ffh <spam frankhirsch.net> writes:
Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/
 
 Please digg and reddit.
 
 BA

You want multicast? Well, for multicast functions (with one parameter) it seems to be rather straightforward template programming: ---<snip>--- module multicastFunctions; template mcf(T) { class mcf { void function(T) fun; mcf next; void opCall(T x) { fun(x); if (next !is null) next(x); } mcf opCat(mcf n) { mcf m=this.dup(); m.next=n.dup(); return m; } mcf dup() { return new mcf(this); } this(mcf m) { this(m.fun,m.next); } this(void function(T) d,mcf n=null) { fun=d; next=n; } } } void fa(int x) { printf("fa(%i)\n",x); } void fb(int x) { printf("fb(%i)\n",x); } void main() { mcf!(int) a=new mcf!(int)(&fa); mcf!(int) b=new mcf!(int)(&fb); mcf!(int) c=a~b; a(1); b(2); c(3); } ---<snap>--- I am sure with all the templating wizzards floating around here someone can come up with something that is not quite as full of crap as my little proof of concept code, probably with multiple parameter feature and whatnot; dirty and obvious hack for multi parm would be to have N copies of the template for 0..N-1 parms. Look ma, no C#! Regards, Frank
Sep 11 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"0ffh" <spam frankhirsch.net> wrote in message 
news:fc6mea$4d8$1 digitalmars.com...
 Brad Anderson wrote:
 I am sure with all the templating wizzards floating around here
 someone can come up with something that is not quite as full of
 crap as my little proof of concept code, probably with multiple
 parameter feature and whatnot; dirty and obvious hack for multi
 parm would be to have N copies of the template for 0..N-1 parms.

Oh please, D has variadic templates :D That, and I'd expect something like this to be a value type. struct MCD(Args...) { void function(Args)[] funcs; void opCatAssign(void function(Args) f) { funcs ~= f; } void opCall(Args args) { foreach(f; funcs) f(args); } } void fa(int x) { Stdout.formatln("fa({})", x); } void fb(int x) { Stdout.formatln("fb({})", x); } void main() { MCD!(int) a; a ~= &fa; a ~= &fb; a(3); }
Sep 11 2007
parent reply Brad Anderson <brad dsource.org> writes:
Jarrett Billingsley wrote:
 Brad Anderson wrote:
 I am sure with all the templating wizzards floating around here
 someone can come up with something that is not quite as full of
 crap as my little proof of concept code, probably with multiple
 parameter feature and whatnot; dirty and obvious hack for multi
 parm would be to have N copies of the template for 0..N-1 parms.

Oh please, D has variadic templates :D That, and I'd expect something like this to be a value type.

It is quoted a bit like I wrote this blog post, but I did not. I'm just the marketing guy here. BA
Sep 11 2007
next sibling parent 0ffh <spam frankhirsch.net> writes:
Brad Anderson wrote:
 It is quoted a bit like I wrote this blog post, but I did not.  I'm just
 the marketing guy here.

Ups, sorry, my mistake! Regards, Frank
Sep 12 2007
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Brad Anderson" <brad dsource.org> wrote in message 
news:fc7kh6$1jin$1 digitalmars.com...

 Jarrett Billingsley wrote:
 Brad Anderson wrote:
 I am sure with all the templating wizzards floating around here


It is quoted a bit like I wrote this blog post, but I did not. I'm just the marketing guy here.

Oops, misquote there. Should've been 0ffh.
Sep 12 2007
prev sibling next sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/
 
 Please digg and reddit.
 
 BA

Reddit: http://programming.reddit.com/info/2o4we/comments Digg: http://www.digg.com/programming/D_doesn_t_have_real_closures
Sep 11 2007
prev sibling parent reply =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/

I've posted a response on my blog: http://jcesar.totumo.net/2007/09/13/d-should-have-real-closures/ Comments? Thanks
Sep 12 2007
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Julio CÚsar Carrascal Urquijo wrote:
 Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/

I've posted a response on my blog: http://jcesar.totumo.net/2007/09/13/d-should-have-real-closures/ Comments? Thanks

On reddit: http://programming.reddit.com/new
Sep 13 2007
parent =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
Walter Bright wrote:
 On reddit:
 
 http://programming.reddit.com/new

Thank you for posting it. Here's the direct link: http://programming.reddit.com/info/2oyuz/comments
Sep 13 2007
prev sibling next sibling parent reply Russell Lewis <webmaster villagersonline.com> writes:
Julio CÚsar Carrascal Urquijo wrote:
 Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/

I've posted a response on my blog: http://jcesar.totumo.net/2007/09/13/d-should-have-real-closures/

I think that closures could be easily implemented using compiler-driven currying. I'm thinking that we should add the syntax curry <exp> which would be valid inside delegate and function literals, and which is defined to mean: "The value of <exp> is evaluated at delegate literal creation time, and stored on the heap, then passed to the delegate literal at call time as a curried argument." Basically, the compiler would take all of the curry expressions in a literal, build a struct on the heap which contained them, then pass a pointer to that struct as a curried argument to the delegate. The thing I like about this is that it makes it obvious which arguments are passed on the heap (curry expressions) and which access stack variables (ordinary, non-curry expressions). And it's compact enough that I think it could see practical use. EXAMPLES Let's start with a simple example. You have an integer that you want to return to anybody who calls your delegate: int delegate() Foo() { int i = <whatever>; return delegate int() { return curry i; } } Now, something more complex, where you use a curry expression in the left-hand side of an assignment (and note that you can use curry expressions on function arguments): void delegate(int) BuildAssigner(int *ptr) { return delegate void(int newVal) { *(curry ptr) = newVal; }; } Something which copies values from one to another (such as binding two things together in your GUI): void delegate() BuildDelayedCopier(int *dest,int *src) { return delegate void() { *(curry dest) = *(curry src); }; } Thoughts, anyone?
Sep 13 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Russell,

 I think that closures could be easily implemented using
 compiler-driven
 currying.  I'm thinking that we should add the syntax
 curry <exp>
 which would be valid inside delegate and function literals, and which
 is
 defined to mean:
 

I like this idea. This would cover most cases where you want to have a persistent delegate. However it wouldn't cover the cases where the action is expected to modify function state. However most of the time you wont want to do that in a persistent delegate. What is more likely is that you will want to create two delegates with shared persistent state. But then you might as well generate a struct. Which, come to think of it, get back to the Idea I have always liked; delegate literals from arbitrary scope. void fn() { struct S { int i; int j; int at; }; S* s = new S // darn I want anon structs alias s this; // might this work? i = 5; j = 10; Funky(s.{at = i;}, s.{at++; return at > j;} s.{return at;}); //make three delegates that uses 's' as context ptr. }
Sep 13 2007
parent Russell Lewis <webmaster villagersonline.com> writes:
BCS wrote:
 Reply to Russell,
 
 I think that closures could be easily implemented using
 compiler-driven
 currying.  I'm thinking that we should add the syntax
 curry <exp>
 which would be valid inside delegate and function literals, and which
 is
 defined to mean:

I like this idea. This would cover most cases where you want to have a persistent delegate. However it wouldn't cover the cases where the action is expected to modify function state. However most of the time you wont want to do that in a persistent delegate. What is more likely is that you will want to create two delegates with shared persistent state. But then you might as well generate a struct. Which, come to think of it, get back to the Idea I have always liked; delegate literals from arbitrary scope.

I thought about these issues, but decided to not include them in the original post for simplicity. :) I wanted to amplify and formalize a *VERY COOL* syntax that you used in your example below, which I call "pseudo-member" syntax: DEFINITION The "pseudo-member" syntax is defined as: <structOrClassVariable>.delegate <retVal>(<args>) { <body> } to be syntax sugar for the following: delegate <retVal>(<args>) { auto this = curry <structOrClassVariable>; <modifiedBody> } where <modifiedBody> is the same as <body> except that, the expressions within are modified to use "this.<member>" as appropriate. EXAMPLE struct Foo { int a,b,c; } void delegate(int) BuildSettor(Foo *ptr) { return ptr.delegate void(int val) { a = b = c = val; } // the line above is equivalent to: return delegate void(int val) { auto this = curry val; this.a = this.b = this.c = val; } } NOTE: This syntax would *NOT* give access to private fields. Since it is simply syntax sugar for a delegate literal, it is limited to the access rights of the creator.
 void fn()
 {
   struct S
   {
     int i;
     int j;
     int at;
   };
 
   S* s = new S  // darn I want anon structs
   alias s this; // might this work?
 
   i = 5;
   j = 10;
 
   Funky(s.{at =  i;}, s.{at++; return at > j;} s.{return at;}); //make 
 three delegates that uses 's' as context ptr.
 }

Sep 13 2007
prev sibling parent reply Guillaume B. <guillaume.b.spam spam.spam> writes:
Julio CÚsar Carrascal Urquijo Wrote:

 Brad Anderson wrote:
 http://www.hans-eric.com/2007/09/11/d-doesnt-have-real-closures/

I've posted a response on my blog: http://jcesar.totumo.net/2007/09/13/d-should-have-real-closures/ Comments? Thanks

I'm pretty much new to D but I've recently found std.bind.bind() and while it's not as nice, it seems to work: ========== import std.stdio; import std.bind; class Event { private void delegate()[] m_Delegate; public void opCatAssign(void delegate() dg) { m_Delegate ~= dg; } public void fireEvent() { foreach (dg; m_Delegate) { dg(); } } } void bindEvent(T)(ref Event event, ref T source, ref T target) { void f(ref T source, ref T target) { writefln("target: %s = source: %s", target, source); } event ~= bind(&f, source, target).ptr; } void bindSomeEvent(Event event, char[] s) { auto source = "source" ~ s; auto target = s ~ "target"; bindEvent(event, source, target); } void main() { auto e = new Event(); bindSomeEvent(e, "1"); bindSomeEvent(e, "2"); bindSomeEvent(e, "3"); e.fireEvent(); } ========== Is there something wrong with this? ... Well, real closures would be much nicer, but I want to know if I'm missing something... Thanks, Guillaume
Sep 13 2007
parent =?ISO-8859-1?Q?Julio_C=E9sar_Carrascal_Urquijo?= writes:
Guillaume B. wrote:
 Is there something wrong with this? ... Well, real closures would be much
 nicer, but I want to know if I'm missing something...
 
  Thanks,
 
  Guillaume

Yes, first you are binding function arguments. In the inner function you can't use the outer function's variables without passing them as arguments and if you accidentally use one of them the compiler wont help you detect it. The second problem is that it's too cumbersome to use. The easier it is to use a feature the more uses you'll find. One of the examples in the article is ported from JavaScript where it is wildly used for it's elegance and because it works. It works in D but I don't think any D programmer will use it because it looks horrible in D. If you force a programmer to bind all variables to get something that works like a closure he'll settle with another alternative. That's the problem I see.
Sep 13 2007