Defer in D

2016-03-19 Thread Xinok via Digitalmars-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

2016-03-20 Thread Nick Treleaven via Digitalmars-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

2016-03-20 Thread Bauss via Digitalmars-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

2016-03-20 Thread Nick Treleaven via Digitalmars-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

2016-03-21 Thread angel via Digitalmars-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

2016-03-21 Thread Nick Treleaven via Digitalmars-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

2016-03-21 Thread Dmitry Olshansky via Digitalmars-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

2016-03-21 Thread Xinok via Digitalmars-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