digitalmars.D - Suggestion: "new delegate" - delegates useable outside of the nesting
- Burton Radons (11/11) Jun 02 2006 I use delegates a lot but the fact that they can only live until the end...
- Jarrett Billingsley (26/37) Jun 02 2006 Haha, funny thing is, I'm implementing this _exact_ feature with virtual...
- Markus Dangl (15/34) Jun 14 2006 You might find my "AdvancedDelegate" library useful, i recently posted
- Jarrett Billingsley (3/7) Jun 14 2006 I have been eyeing that ;)
- Tom S (7/24) Jun 14 2006 Hmm.. what's stopping you from returning a 'normal' delegate, thru
- Markus Dangl (20/24) Jun 15 2006 The Eval() method is there to really do the evaluation of the delegate.
- Walter Bright (7/20) Jun 02 2006 Unfortunately, it's quite a bit more work than that. You have to copy
- Jarrett Billingsley (9/11) Jun 02 2006 This, at least, seems to be a requirement of static closures. In Lua, w...
- Walter Bright (3/16) Jun 02 2006 Sure, you can design the language that way. But I've had uses for ones
- Burton Radons (19/43) Jun 02 2006 Good points (I forgot about multiple nesting - did I ever compliment you...
- Walter Bright (3/33) Jun 02 2006 What about the px problem above? This wouldn't occur in Python which
- Burton Radons (24/62) Jun 03 2006 What about if the user calls a nested function outside of the nesting
- Tom S (3/4) Jun 03 2006 Please, don't use suspicious whitespace sequences ! LOL
- Daniel Keep (11/18) Jun 03 2006 Wow. That's one touchy virus scanner. I never knew that whitespace was
I use delegates a lot but the fact that they can only live until the end of the nesting function scope means I need to use classes in many cases, which is a lot more typing (and fluff telling the autodoc that it's not part of the public API, and other problems) when it could be easily fixed. The syntax change would be very simple: dispatcher.add (new delegate void (Event event) { ... }); And the effect would be simple as well: duplicate the calling context's stack to the extent that the delegate can see it and use the duplicated pointer as the "this" pointer; otherwise it's a regular nested delegate. Five minutes work max, very topical changes, explicit allocation, big benefits. Is good!
Jun 02 2006
"Burton Radons" <burton-radons smocky.com> wrote in message news:e5qkhd$2a1u$1 digitaldaemon.com...I use delegates a lot but the fact that they can only live until the end of the nesting function scope means I need to use classes in many cases, which is a lot more typing (and fluff telling the autodoc that it's not part of the public API, and other problems) when it could be easily fixed. The syntax change would be very simple: dispatcher.add (new delegate void (Event event) { ... }); And the effect would be simple as well: duplicate the calling context's stack to the extent that the delegate can see it and use the duplicated pointer as the "this" pointer; otherwise it's a regular nested delegate. Five minutes work max, very topical changes, explicit allocation, big benefits. Is good!Haha, funny thing is, I'm implementing this _exact_ feature with virtually the same syntax in a small D-like scripting language I'm writing, although I use 'function' instead of 'delegate' (as there is no distinction between the two in my language). This feature is called "static closures," and is very useful indeed. D's dynamic closures (that is, the context for the nested function exists as long as its owning function doesn't return) are fairly useful, but have the one major downside which you point out. Implementing static closures in D would be an interesting proposition, as they would technically be objects, though implicitly. Then there's the problem with RAII class references. Consider something like: char delegate() createFileReader(char[] fileName) { auto File f = new File(fileName, FileMode.In); return new delegate char() { return f.getc(); }; } This function would return a function that would be used to read (very simply) a file, one character at a time. The problem is that the File reference in the enclosing scope could not be deleted when createFileReader returns. I suppose the way around this would be to disallow using RAII class references inside static closures, but..
Jun 02 2006
Implementing static closures in D would be an interesting proposition, as they would technically be objects, though implicitly. Then there's the problem with RAII class references. Consider something like: char delegate() createFileReader(char[] fileName) { auto File f = new File(fileName, FileMode.In); return new delegate char() { return f.getc(); }; } This function would return a function that would be used to read (very simply) a file, one character at a time. The problem is that the File reference in the enclosing scope could not be deleted when createFileReader returns. I suppose the way around this would be to disallow using RAII class references inside static closures, but..You might find my "AdvancedDelegate" library useful, i recently posted it to the announce newsgroup. Using its templates for partial application of functions and delegates, you can do something very similiar to the code above: AdvancedDelegate0!(char) createFileReader(char[] fileName) { auto File f = new File(fileName, FileMode.In); auto readerFunc = AdvancedDelegate( function char(File f) { return f.getc(); } ); return readerFunc(f); }
Jun 14 2006
"Markus Dangl" <danglm in.tum.de> wrote in message news:e6pr8e$28k3$1 digitaldaemon.com...You might find my "AdvancedDelegate" library useful, i recently posted it to the announce newsgroup. Using its templates for partial application of functions and delegates, you can do something very similiar to the code above:I have been eyeing that ;)
Jun 14 2006
Markus Dangl wrote:You might find my "AdvancedDelegate" library useful, i recently posted it to the announce newsgroup. Using its templates for partial application of functions and delegates, you can do something very similiar to the code above: AdvancedDelegate0!(char) createFileReader(char[] fileName) { auto File f = new File(fileName, FileMode.In); auto readerFunc = AdvancedDelegate( function char(File f) { return f.getc(); } ); return readerFunc(f); }Hmm.. what's stopping you from returning a 'normal' delegate, thru return &readerFunc(f).Eval or &readerFunc(f).opCall ? it would make more sense to functions which accept char delegate() and have no idea what AdvancedDelegate0!(char) is :) -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jun 14 2006
Hmm.. what's stopping you from returning a 'normal' delegate, thru return &readerFunc(f).Eval or &readerFunc(f).opCall ? it would make more sense to functions which accept char delegate() and have no idea what AdvancedDelegate0!(char) is :)The Eval() method is there to really do the evaluation of the delegate. You can easily "convert" an AdvancedDelegate to a delegate by referencing its Eval() method: char delegate() createFileReader(char[] fileName) { File f = new File(fileName, FileMode.In); auto readerFunc = AdvancedDelegate( function char(File f) { return f.getc(); } ); return &(readerFunc(f).Eval); } I see that this isn't very intuitive, so i'm going to add a "GetDelegate" method and overload the "opCast" operator - you can then also write: return readerFunc(f).GetDelegate; or: return cast(char delegate()) (readerFunc(f));
Jun 15 2006
Burton Radons wrote:I use delegates a lot but the fact that they can only live until the end of the nesting function scope means I need to use classes in many cases, which is a lot more typing (and fluff telling the autodoc that it's not part of the public API, and other problems) when it could be easily fixed. The syntax change would be very simple: dispatcher.add (new delegate void (Event event) { ... }); And the effect would be simple as well: duplicate the calling context's stack to the extent that the delegate can see it and use the duplicated pointer as the "this" pointer; otherwise it's a regular nested delegate. Five minutes work max, very topical changes, explicit allocation, big benefits. Is good!Unfortunately, it's quite a bit more work than that. You have to copy all the frames of the lexically enclosing functions, too. Then you have the issue of updates to the framed variable copies not being reflected in the stack variables. Then there's the problem of things like: int x; int* px = &x;
Jun 02 2006
"Walter Bright" <newshound digitalmars.com> wrote in message news:e5qli2$2ale$1 digitaldaemon.com...Then you have the issue of updates to the framed variable copies not being reflected in the stack variables.This, at least, seems to be a requirement of static closures. In Lua, which supports them, when you instantiate a static closure, the values it uses from enclosing scopes ("upvalues") are "frozen" - they are copied into the closure's instance. Then, updating the value using the closure doesn't affect the original variable. This is an important feature so that multiple instances of closures can be created which don't step on each others' toes, so to speak.
Jun 02 2006
Jarrett Billingsley wrote:"Walter Bright" <newshound digitalmars.com> wrote in message news:e5qli2$2ale$1 digitaldaemon.com...Sure, you can design the language that way. But I've had uses for ones that *did* update the local variables.Then you have the issue of updates to the framed variable copies not being reflected in the stack variables.This, at least, seems to be a requirement of static closures. In Lua, which supports them, when you instantiate a static closure, the values it uses from enclosing scopes ("upvalues") are "frozen" - they are copied into the closure's instance. Then, updating the value using the closure doesn't affect the original variable. This is an important feature so that multiple instances of closures can be created which don't step on each others' toes, so to speak.
Jun 02 2006
Walter Bright wrote:Burton Radons wrote:Good points (I forgot about multiple nesting - did I ever compliment you for putting that in with the first release containing nested functions? - but you need to chain anyway so the logic must already be in there to piggyback onto), it is more work but compare it to the work required when it's omitted. I have done terrible things, committed sins against good engineering just because my nesting scope exits, and while it hasn't had a cooling effect on me, I'm sure there have been other people who have resorted to inferior Java class-inheritance techniques just to get around this problem. I have to admit I've done it once or twice. I was young and naive! Frozen variables are, of course, a feature, not a bug, and one the user would opt into by using the "new" variant. We discussed this in 2003. ;-) Anyway in three years and four months I haven't depended on the nesting scope's variables varying once, and while I haven't really wanted them to be frozen either, I've used it a few times in languages which freeze the nesting scopes (like Python). The only really good argument against this originally, in my opinion, was that it was a hidden allocation, but it's explicit like this.I use delegates a lot but the fact that they can only live until the end of the nesting function scope means I need to use classes in many cases, which is a lot more typing (and fluff telling the autodoc that it's not part of the public API, and other problems) when it could be easily fixed. The syntax change would be very simple: dispatcher.add (new delegate void (Event event) { ... }); And the effect would be simple as well: duplicate the calling context's stack to the extent that the delegate can see it and use the duplicated pointer as the "this" pointer; otherwise it's a regular nested delegate. Five minutes work max, very topical changes, explicit allocation, big benefits. Is good!Unfortunately, it's quite a bit more work than that. You have to copy all the frames of the lexically enclosing functions, too. Then you have the issue of updates to the framed variable copies not being reflected in the stack variables. Then there's the problem of things like: int x; int* px = &x;
Jun 02 2006
Burton Radons wrote:Walter Bright wrote:What about the px problem above? This wouldn't occur in Python which doesn't have pointers, but it sure happens in D.Unfortunately, it's quite a bit more work than that. You have to copy all the frames of the lexically enclosing functions, too. Then you have the issue of updates to the framed variable copies not being reflected in the stack variables. Then there's the problem of things like: int x; int* px = &x;Good points (I forgot about multiple nesting - did I ever compliment you for putting that in with the first release containing nested functions? - but you need to chain anyway so the logic must already be in there to piggyback onto), it is more work but compare it to the work required when it's omitted. I have done terrible things, committed sins against good engineering just because my nesting scope exits, and while it hasn't had a cooling effect on me, I'm sure there have been other people who have resorted to inferior Java class-inheritance techniques just to get around this problem. I have to admit I've done it once or twice. I was young and naive! Frozen variables are, of course, a feature, not a bug, and one the user would opt into by using the "new" variant. We discussed this in 2003. ;-) Anyway in three years and four months I haven't depended on the nesting scope's variables varying once, and while I haven't really wanted them to be frozen either, I've used it a few times in languages which freeze the nesting scopes (like Python). The only really good argument against this originally, in my opinion, was that it was a hidden allocation, but it's explicit like this.
Jun 02 2006
Walter Bright wrote:Burton Radons wrote:What about if the user calls a nested function outside of the nesting scope? They both have pitfalls. I don't really want to mention it, but if you invert the logic it continues to act the same without this pitfall; the only change is that you can call the nested function outside of the nesting scope. What I mean is that instead of just passing the delegate a pointer to the frame, allocate the frame at the start if it or a nested scope has a "new delegate" and use that for both the delegate and that scope: float bar = 6; void delegate () dg = new delegate void () { bar = 8; } Becomes: struct Delegate { void *self, func; } struct Frame { float bar; Delegate dg; } Frame *frame = new Frame; Delegate dg; frame.bar = 6; frame.dg = Delegate { frame, function void (Frame *frame) { frame.bar = 8; } }; Oh no, it's all syntax sugar! :-) The logic for doing this should mostly already be in the code. This might be well-justified because it makes nested functions behave consistently, and with some more effort it would only allocate a frame containing variables the nesting functions actually use.Walter Bright wrote:What about the px problem above? This wouldn't occur in Python which doesn't have pointers, but it sure happens in D.Unfortunately, it's quite a bit more work than that. You have to copy all the frames of the lexically enclosing functions, too. Then you have the issue of updates to the framed variable copies not being reflected in the stack variables. Then there's the problem of things like: int x; int* px = &x;Good points (I forgot about multiple nesting - did I ever compliment you for putting that in with the first release containing nested functions? - but you need to chain anyway so the logic must already be in there to piggyback onto), it is more work but compare it to the work required when it's omitted. I have done terrible things, committed sins against good engineering just because my nesting scope exits, and while it hasn't had a cooling effect on me, I'm sure there have been other people who have resorted to inferior Java class-inheritance techniques just to get around this problem. I have to admit I've done it once or twice. I was young and naive! Frozen variables are, of course, a feature, not a bug, and one the user would opt into by using the "new" variant. We discussed this in 2003. ;-) Anyway in three years and four months I haven't depended on the nesting scope's variables varying once, and while I haven't really wanted them to be frozen either, I've used it a few times in languages which freeze the nesting scopes (like Python). The only really good argument against this originally, in my opinion, was that it was a hidden allocation, but it's explicit like this.
Jun 03 2006
Burton Radons wrote:(...)Please, don't use suspicious whitespace sequences ! LOL http://158.75.59.9/~h3/tmp/lolAtAvast.png
Jun 03 2006
Tom S wrote:Burton Radons wrote:Wow. That's one touchy virus scanner. I never knew that whitespace was so dangerous (well, I suppose if you feed to the http://en.wikipedia.org/wiki/Whitespace_programming_language interpreter, it might be). -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/(...)Please, don't use suspicious whitespace sequences ! LOL http://158.75.59.9/~h3/tmp/lolAtAvast.png
Jun 03 2006