digitalmars.D - Defer in D
- Xinok (16/16) Mar 19 2016 I stumbled upon an example demonstrating defer in Go which I
- Nick Treleaven (6/12) Mar 20 2016 Nice! This is more flexible than Go's defer as you can have more
- Bauss (9/23) Mar 20 2016 No that's not the same, since the reference to i does not change
- Nick Treleaven (10/21) Mar 20 2016 Thanks. So we need the lambda to capture args (below) rather than
- Nick Treleaven (8/12) Mar 21 2016 Maybe this method would be nice (does the same thing):
- angel (5/5) Mar 21 2016 I would, actually, like to see it integrated with the core
- Dmitry Olshansky (15/26) Mar 21 2016 The main use case in Go that needs it specifically as a function level
- Xinok (9/23) Mar 21 2016 D and Go have different mechanisms for handling
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?
Mar 19 2016
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/23c665bdae9eNice! 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).
Mar 20 2016
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: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.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/23c665bdae9eNice! 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).
Mar 20 2016
On 20/03/2016 16:18, Bauss wrote:(or on my laptop)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.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.
Mar 20 2016
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.
Mar 21 2016
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.
Mar 21 2016
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/13I 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
Mar 21 2016
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
Mar 21 2016