September 13, 2007
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?
September 13, 2007
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.
}


September 13, 2007
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.
> }
September 13, 2007
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

September 14, 2007
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.
1 2
Next ›   Last »