digitalmars.D - Anonymous Delegates
- Erik Lechak (50/50) Jun 16 2008 Hello all,
- Lutger (15/23) Jun 16 2008 Anonymous delegates do have of sort-of-this pointer: the stack frame.
- Russell Lewis (64/68) Jun 16 2008 Not having used gtk much, I'll assume that the Button object passed to
- Milke Wey (4/8) Jun 16 2008 Yes this is the case, but b != this.
- Nick Sabalausky (86/97) Jun 16 2008 In D1 and D2, what happens if you do something like this:
- Jason House (3/37) Jun 16 2008 I believe converting from function to delegate is no problem, but the re...
- Nick Sabalausky (34/81) Jun 16 2008 I see. The talk about D2's closures creating a copy of the stack frame m...
- Nick Sabalausky (18/103) Jun 16 2008 Although, come to think of it, if member-function-syntax (is that what i...
- Russell Lewis (4/23) Jun 16 2008 Many people have asked for this; we haven't yet been able to convince
- downs (2/26) Jun 17 2008 Afaik, the closest you can come is repeat(7) = { writefln("Calling callb...
- Russell Lewis (16/22) Jun 16 2008 We don't have implicit conversion of function pointers to delegates,
Hello all, This is a trivial example that got me excited about delegates: import std.stdio; class Dog{ string name; this( string name){ this.name = name; } void printName(){ writefln(name); } } int main(string [] args){ Dog kippy = new Dog("kippy"); void delegate() name = &kippy.printName; name(); return 0; } Now for some real-world gtk stuff. What does the anonymous delegate buy me in the next bit of code. Even if it wasn't a super trivial callback, I don't know why it is better as a delegate than a function pointer. Button b = cast(Button)g.getWidget("button1"); b.addOnClicked( delegate void(Button aux){ exit(0); } ); I found myself using the equivalent C code to connect the widget to the callback, but I want to do it the D ( or at least the gtkd ) way. But it just seems to complicate the code without reason. I though maybe I could do this: b.addOnClicked( delegate void(Button aux){ this.doSomethingAButtonCanDo(); } ); And somehow the the callback would populate the 'this' variable with the button that generated the callback. But instead I get a compile-time error: Error: 'this' is only allowed in non-static member functions, not __dgliteral1. So if anonymous delegates don't (can't) have an object associated with them, why do they exist if they are functionally equivalent to a function pointer? Or are they not equivalent? Then I thought maybe I could cast a callback function to a delegate. So at least at some point in the future the signal_autoconnect feature might work, and I could easily remove the manual registration of callbacks. But I just get this error: conversion to non-scalar type requested. void bc(Button a){ writefln("adsf"); } b.addOnClicked( cast( void delegate(Button)) &bc ); Then I read the following documentation: "If the keywords function or delegate are omitted, it defaults to being a delegate." "and the following where the return type int is inferred:" And I saw this: int abc(int delegate(long i)); void test() { int b = 3; abc( (long c) { return 6 + b; } ); } And this: loop(5, 100, { d += 1; } ); Since delegates have a nice shorthand syntax, they must be more important than I realize. Without an associated object, they just sound like function pointers to me. What am I missing? Thanks, Erik Lechak
Jun 16 2008
Erik Lechak wrote: ...Since delegates have a nice shorthand syntax, they must be more important than I realize. Without an associated object, they just sound like function pointers to me. What am I missing? Thanks, Erik LechakAnonymous delegates do have of sort-of-this pointer: the stack frame. An example is clearest: char[] clickedMessage = "you clicked me!"; button.addOnClicked( (Button aux) { Stdout(clickedMessage).newline; } ); In D1, as long as the scope where clickedMessage lives is valid, the delegate passed to addOnClicked can access any variable in it. This can result in weird bugs of course when that scope is no longer valid, but also makes delegates very fast. In D2 on the other hand, I believe this will result in a closure, heap-allocating the surrounding stack frame and storing it with the delegate. Correct me if I'm wrong, I haven't used this yet.
Jun 16 2008
Erik Lechak wrote:I though maybe I could do this: b.addOnClicked( delegate void(Button aux){ this.doSomethingAButtonCanDo(); } );Not having used gtk much, I'll assume that the Button object passed to the callback is the same button as the variable 'b' in your attempt above. So if you want 'b' to call doSomethingAButtonCanDo() when it is clicked, then you could write: BEGIN CODE b.addOnClicked( delegate void(Button ignored) { b.doSomethingAButtonCanDo(); }); END CODE or, since the argument is the same button, this also works: BEGIN CODE b.addOnClicked( delegate void(Button aux) { aux.doSomethingAButtonCanDo(); }); END CODE This still seems a little bit useless. But as you get more advanced, whole new worlds open up. Let's look at how we might change the gtk API to be more delegate-aware. Since a delegate can carry with it some context, we could remove the Button argument from the callback: BEGIN CODE b.addOnClicked_noArg( &b.doSomethingAButtonCanDo ); END CODE Notice that the syntax above constructs a delegate with 'b' as the 'this' pointer, and 'doSomethingAButtonCanDo' as the function. The cool thing, of course, is that you can pass delegates which point to any other type of object, so long as the delegate takes no arguments. For instance: BEGIN CODE SomeWindowClass w = GetSomeSpecificWindow(); b.addOnClicked_noArg( &w.closeWindow ); END CODE Now you see that (in D2, which has full and automatic closure support), an anonymous delegate is just another cool thing that can be passed: BEGIN CODE SomeInterestingValue v = <whatever>; SomeWindowClass w = GetSomeSpecificWindow(); b.addOnClicked_noArg({ w.setSomeProperty(v) }); END CODE Note that in the above example, the 'this' pointer will point to the automatically-allocated heap frame, which will store your 'v' and 'w' variables, and when the delegate is called, that one-line function will be executed. In my experience, the more that I port my code (and my callbacks) to use delegates, the more amazing things get. It's sometimes hard to see why they are so important in trivial examples...but imagine that you were carrying around a few dozen local variables. Then delegates (and closures in particular) get *really* nice. BEGIN CODE void myFunction(<some arguments>) { <set some variables> CallLibraryFunction( delegate void(<some more arguments>) { <do something nontrivial which includes all the args & vars above> }); } END CODE
Jun 16 2008
On Mon, 2008-06-16 at 07:25 -0700, Russell Lewis wrote:Not having used gtk much, I'll assume that the Button object passed to the callback is the same button as the variable 'b' in your attempt above.Yes this is the case, but b != this. -- Mike Wey
Jun 16 2008
"Russell Lewis" <webmaster villagersonline.com> wrote in message news:g35t4n$22n6$1 digitalmars.com...Now you see that (in D2, which has full and automatic closure support), an anonymous delegate is just another cool thing that can be passed: BEGIN CODE SomeInterestingValue v = <whatever>; SomeWindowClass w = GetSomeSpecificWindow(); b.addOnClicked_noArg({ w.setSomeProperty(v) }); END CODE Note that in the above example, the 'this' pointer will point to the automatically-allocated heap frame, which will store your 'v' and 'w' variables, and when the delegate is called, that one-line function will be executed.In D1 and D2, what happens if you do something like this: class MyClass { int delegate() callback; void registerCallback(int delegate() callback) { this.callback = callback; } void display() { writefln("{0}", callback()); } } void foo() { int val; auto c = new MyClass(); val = 1; c.registerCallback({ return val; }) val = 2; c.display(); // Does this display "1" or "2"? } In D1 and D2, does that display "1" or "2"? As long as I'm asking about delegate stuff, something else I've been wondering too: I know this following syntax for calling a function isn't supported, but is there any technical reason preventing it from being possible?: // Note that the delegate is the last parameter: void repeat(int times, int delegate() body) { // BTW, is "auto" omittable here? I didn't // think so, but the example here omits it: // http://www.digitalmars.com/d/2.0/statement.html#ForeachRangeStatement for(auto i; 0..times) body(); } void foo() { // Current method of calling, ugly: repeat(7, { writefln("Calling Callback"); }); // Not currently allowed, but is it possibly doable? // Much nicer-looking. repeat(7) { writefln("Calling Callback"); } } Sorry if I already brought that up before, I can't remember if I did or not. Or, maybe for the sake of language consistency it could do something like this: void myfunc(int a, int b, void delegate() foo1, void delegate() foo2, void delegate() foo3) { // Do stuff } // Standard way: myfunc(1, 2, { /+ do stuff 1 +/ }, { /+ do stuff 2 +/ }, { /+ do stuff 3 +/ }); // Crazy Fancy way inspired by the // function contract "in{}out{}body{}" stuff: myfunc() foo1 { // do stuff 1 } a: /+expression here+/, b { // Do stuff return /+expression here+/; } foo3 { // do stuff 3 } foo2 { // do stuff 2 }
Jun 16 2008
Nick Sabalausky Wrote:In D1 and D2, what happens if you do something like this: class MyClass { int delegate() callback; void registerCallback(int delegate() callback) { this.callback = callback; } void display() { writefln("{0}", callback()); } } void foo() { int val; auto c = new MyClass(); val = 1; c.registerCallback({ return val; }) val = 2; c.display(); // Does this display "1" or "2"? } In D1 and D2, does that display "1" or "2"?It will print "2". The internal context pointer refers to the stack frame from foo. When the delegate is called, it'll look up val and find the value of 2. If you want to get the value of 1, you'll need to bind val to the call... or find a way to make capturing a variable by value work for you. I don't remember if full closures are part of the latest dmd v1 compiler or if it's just dmd v2.As long as I'm asking about delegate stuff, something else I've been wondering too: I know this following syntax for calling a function isn't supported, but is there any technical reason preventing it from being possible?:I believe converting from function to delegate is no problem, but the reverse is. I believe functions exist for compatibility with C where just a function pointer is passed in.
Jun 16 2008
"Jason House" <jason.james.house gmail.com> wrote in message news:g36f18$lmr$1 digitalmars.com...Nick Sabalausky Wrote:I see. The talk about D2's closures creating a copy of the stack frame made me wonder if that meant anonymous delegates *normally* acted on a copy of the original stack frame (would have printed "1") or on the actual stack frame itself (prints "2").In D1 and D2, what happens if you do something like this: class MyClass { int delegate() callback; void registerCallback(int delegate() callback) { this.callback = callback; } void display() { writefln("{0}", callback()); } } void foo() { int val; auto c = new MyClass(); val = 1; c.registerCallback({ return val; }) val = 2; c.display(); // Does this display "1" or "2"? } In D1 and D2, does that display "1" or "2"?It will print "2". The internal context pointer refers to the stack frame from foo. When the delegate is called, it'll look up val and find the value of 2. If you want to get the value of 1, you'll need to bind val to the call... or find a way to make capturing a variable by value work for you.I don't remember if full closures are part of the latest dmd v1 compiler or if it's just dmd v2.According to the docs, full closures are D2-only. In the section "Delegates, Function Pointers, and Closures": D1 docs: http://www.digitalmars.com/d/1.0/function.html "The stack variables, however, are not valid once the function declaring them has exited, in the same manner that pointers to stack variables are not valid upon exit from a function:" D2 docs: http://www.digitalmars.com/d/2.0/function.html "The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error."That's not what I was referring to. I meant that if you have a function that takes a delegate as a paramater, then it would be nice (if it would even be possible for the language to allow this) to rewrite a call to that function like this: // From this: // (Current method of calling, ugly) repeat(7, { writefln("Calling Callback"); }); // To this (Syntactical sugar): // (Not currently allowed, but is it possibly doable? // Much nicer-looking.) repeat(7) { writefln("Calling Callback"); }As long as I'm asking about delegate stuff, something else I've been wondering too: I know this following syntax for calling a function isn't supported, but is there any technical reason preventing it from being possible?:I believe converting from function to delegate is no problem, but the reverse is. I believe functions exist for compatibility with C where just a function pointer is passed in.
Jun 16 2008
"Nick Sabalausky" <a a.a> wrote in message news:g36kpk$15rb$1 digitalmars.com..."Jason House" <jason.james.house gmail.com> wrote in message news:g36f18$lmr$1 digitalmars.com...Although, come to think of it, if member-function-syntax (is that what it's called?) ever gets expanded from arrays to all types, then you'd probably be able to do something like this: { writefln("Calling Callback"); }.repeat(7); Which still isn't quite as nice, but it's (arguably) an improvement over the current style. Although, it would require repeat()'s paramaters to be defined in the opposite order (unless the "repeat(7){}" syntax *didn't* require the delegate to be the last param. Or if it just simply required the delegate to be the first param *instead* of requiring it to be the last param as I had originally proposed.) I guess my main point is that I *love* the power that delegates give to D (ex: Easy map/reduce in a C-style language, yay!), but I'm jealous of the incredibly clean syntax that other languages (like ruby and python) provide for their anonymous delegates.Nick Sabalausky Wrote:I see. The talk about D2's closures creating a copy of the stack frame made me wonder if that meant anonymous delegates *normally* acted on a copy of the original stack frame (would have printed "1") or on the actual stack frame itself (prints "2").In D1 and D2, what happens if you do something like this: class MyClass { int delegate() callback; void registerCallback(int delegate() callback) { this.callback = callback; } void display() { writefln("{0}", callback()); } } void foo() { int val; auto c = new MyClass(); val = 1; c.registerCallback({ return val; }) val = 2; c.display(); // Does this display "1" or "2"? } In D1 and D2, does that display "1" or "2"?It will print "2". The internal context pointer refers to the stack frame from foo. When the delegate is called, it'll look up val and find the value of 2. If you want to get the value of 1, you'll need to bind val to the call... or find a way to make capturing a variable by value work for you.I don't remember if full closures are part of the latest dmd v1 compiler or if it's just dmd v2.According to the docs, full closures are D2-only. In the section "Delegates, Function Pointers, and Closures": D1 docs: http://www.digitalmars.com/d/1.0/function.html "The stack variables, however, are not valid once the function declaring them has exited, in the same manner that pointers to stack variables are not valid upon exit from a function:" D2 docs: http://www.digitalmars.com/d/2.0/function.html "The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure. Returning addresses of stack variables, however, is not a closure and is an error."That's not what I was referring to. I meant that if you have a function that takes a delegate as a paramater, then it would be nice (if it would even be possible for the language to allow this) to rewrite a call to that function like this: // From this: // (Current method of calling, ugly) repeat(7, { writefln("Calling Callback"); }); // To this (Syntactical sugar): // (Not currently allowed, but is it possibly doable? // Much nicer-looking.) repeat(7) { writefln("Calling Callback"); }As long as I'm asking about delegate stuff, something else I've been wondering too: I know this following syntax for calling a function isn't supported, but is there any technical reason preventing it from being possible?:I believe converting from function to delegate is no problem, but the reverse is. I believe functions exist for compatibility with C where just a function pointer is passed in.
Jun 16 2008
Nick Sabalausky wrote:That's not what I was referring to. I meant that if you have afunction thattakes a delegate as a paramater, then it would be nice (if it would even be possible for the language to allow this) to rewrite a call to that function like this: // From this: // (Current method of calling, ugly) repeat(7, { writefln("Calling Callback"); }); // To this (Syntactical sugar): // (Not currently allowed, but is it possibly doable? // Much nicer-looking.) repeat(7) { writefln("Calling Callback"); }Many people have asked for this; we haven't yet been able to convince Walter that it is a good idea.
Jun 16 2008
Russell Lewis wrote:Nick Sabalausky wrote:Afaik, the closest you can come is repeat(7) = { writefln("Calling callback back"); } by making repeat return a struct that overloads opAssign. Or opCat. Or whichever you want.That's not what I was referring to. I meant that if you have afunction thattakes a delegate as a paramater, then it would be nice (if it would even be possible for the language to allow this) to rewrite a call to that function like this: // From this: // (Current method of calling, ugly) repeat(7, { writefln("Calling Callback"); }); // To this (Syntactical sugar): // (Not currently allowed, but is it possibly doable? // Much nicer-looking.) repeat(7) { writefln("Calling Callback"); }Many people have asked for this; we haven't yet been able to convince Walter that it is a good idea.
Jun 17 2008
Jason House wrote:We don't have implicit conversion of function pointers to delegates, though people have asked for it. But it's an easy thing to do with an anonymous delegate: BEGIN CODE void function(<args>) my_fp = <whatever>; void delegate(<args>) my_dg = delegate void(<args>) { my_fp(<args>); }; END CODE You can't convert a delegate to a function pointer because a function pointer doesn't have any way to store a 'this' parameter. However, if you need to call a delegate from C code, it's still possible; you simply have to allocate a delegate on the heap (with new), and save the delegate there; pass the pointer to that heap variable as a void* to the C code. Then write an extern(C) wrapper which, given a void*, will turn it into a pointer-to-delegate and then call the delegate.As long as I'm asking about delegate stuff, something else I've been wondering too: I know this following syntax for calling a function isn't supported, but is there any technical reason preventing it from being possible?:I believe converting from function to delegate is no problem, but the reverse is. I believe functions exist for compatibility with C where just a function pointer is passed in.
Jun 16 2008