View mode: basic / threaded / horizontal-split · Log in · Help
September 13, 2007
Re: D doesn't have real closures
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
Re: D doesn't have real closures
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
Re: D doesn't have real closures
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
Re: D doesn't have real closures
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
Re: D doesn't have real closures
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.
Next ›   Last »
1 2
Top | Discussion index | About this forum | D home