Defer in D
I stumbled upon an example demonstrating defer in Go which I thought was interesting. Defer is similar to scope in D except they're called at end of function rather than end of scope; you can queue multiple defer calls by writing them inside of a loop. This implies that it internally builds a stack of delegates which are then executed LIFO once the function returns (or panics). https://tour.golang.org/flowcontrol/13 I took a quick look through Phobos but didn't see anything similar so I wrote this as a proof of concept and to elicit discussion. This also works should the function throw rather than return gracefully. http://dpaste.dzfl.pl/23c665bdae9e I think a library solution is elegant enough that it doesn't need to be built into the language but that doesn't mean it needs to be in Phobos either. Does anybody have a use case for "defer" that isn't already adequately covered by scope statements?
Re: Defer in D
On Saturday, 19 March 2016 at 23:16:40 UTC, Xinok wrote: I took a quick look through Phobos but didn't see anything similar so I wrote this as a proof of concept and to elicit discussion. This also works should the function throw rather than return gracefully. http://dpaste.dzfl.pl/23c665bdae9e Nice! This is more flexible than Go's defer as you can have more than one stack of them. I don't quite get this: defer((int i) => writeln(i), i); If it was defer(() => writeln(i)), would that do the same? (Dpaste won't seem to let me edit your example on my tablet).
Re: Defer in D
On Sunday, 20 March 2016 at 14:11:11 UTC, Nick Treleaven wrote: On Saturday, 19 March 2016 at 23:16:40 UTC, Xinok wrote: I took a quick look through Phobos but didn't see anything similar so I wrote this as a proof of concept and to elicit discussion. This also works should the function throw rather than return gracefully. http://dpaste.dzfl.pl/23c665bdae9e Nice! This is more flexible than Go's defer as you can have more than one stack of them. I don't quite get this: defer((int i) => writeln(i), i); If it was defer(() => writeln(i)), would that do the same? (Dpaste won't seem to let me edit your example on my tablet). No that's not the same, since the reference to i does not change when doing: defer(() => writeln(i)) However with defer((int i) => writeln(i), i) you pass the value of i to the lambda expression which stores the value in a new reference. The problem with the first one is the value will always be the last value of i.
Re: Defer in D
On 20/03/2016 16:18, Bauss wrote: defer((int i) => writeln(i), i); If it was defer(() => writeln(i)), would that do the same? (Dpaste won't seem to let me edit your example on my tablet). (or on my laptop) No that's not the same, since the reference to i does not change when doing: defer(() => writeln(i)) However with defer((int i) => writeln(i), i) you pass the value of i to the lambda expression which stores the value in a new reference. The problem with the first one is the value will always be the last value of i. Thanks. So we need the lambda to capture args (below) rather than capturing i at the callsite: void opCall(ARGS...)(void delegate(ARGS) call, ARGS args) { stack.put(() => call(args)); } The closure above allocates its copy of args on the heap, instead of the callsite closure which captures i by reference.
Re: Defer in D
I would, actually, like to see it integrated with the core language syntax, kinda: scope(function) ... While your solution is viable from the technical point of view, having a consistent language syntax could also be nice.
Re: Defer in D
On 20/03/2016 16:57, Nick Treleaven wrote: void opCall(ARGS...)(void delegate(ARGS) call, ARGS args) { stack.put(() => call(args)); } Maybe this method would be nice (does the same thing): Deferrer d; ... d.capture!writeln("i = ", i); The name capture makes it clearer the arguments are not taken by reference IMO. @Xinok: I suggest for now you put it in a Github repository somewhere.
Re: Defer in D
On 20-Mar-2016 02:16, Xinok wrote: I stumbled upon an example demonstrating defer in Go which I thought was interesting. Defer is similar to scope in D except they're called at end of function rather than end of scope; you can queue multiple defer calls by writing them inside of a loop. This implies that it internally builds a stack of delegates which are then executed LIFO once the function returns (or panics). https://tour.golang.org/flowcontrol/13 I think a library solution is elegant enough that it doesn't need to be built into the language but that doesn't mean it needs to be in Phobos either. Does anybody have a use case for "defer" that isn't already adequately covered by scope statements? The main use case in Go that needs it specifically as a function level primitive is this: files := []File{} for i := paths { files[i], err := os.Open(paths[i]) if err != nil { return errors.Errorf("Failed to open %s", paths[i]) } defer files[i].Close() } ... // lots of code using files So in a nutshell - lack of RAII while operating on collections of resources. -- Dmitry Olshansky
Re: Defer in D
On Monday, 21 March 2016 at 17:46:05 UTC, Dmitry Olshansky wrote: ... The main use case in Go that needs it specifically as a function level primitive is this: files := []File{} for i := paths { files[i], err := os.Open(paths[i]) if err != nil { return errors.Errorf("Failed to open %s", paths[i]) } defer files[i].Close() } ... // lots of code using files So in a nutshell - lack of RAII while operating on collections of resources. D and Go have different mechanisms for handling errors/exceptions. I'll refrain from debating "A is better than B" but I haven't seen any use case which isn't already adequately covered by the existing mechanisms in D. However, one thing I do find inferior is the inability of D lambdas to capture by value. Thus, the simple example of "writeln(i)" may produce unexpected results. @Nick: https://github.com/Xinok/scrapheap/blob/master/defer.d