digitalmars.D - scope(exit) without exception handling?
- "Mehrdad" <wfunction hotmail.com> May 15 2012
- Jonathan M Davis <jmdavisProg gmx.com> May 15 2012
- "Mehrdad" <wfunction hotmail.com> May 15 2012
- Brad Roberts <braddr puremagic.com> May 15 2012
- deadalnix <deadalnix gmail.com> May 16 2012
- Timon Gehr <timon.gehr gmx.ch> May 16 2012
- "Mehrdad" <wfunction hotmail.com> May 15 2012
- "Robert DaSilva" <spunit262 yahoo.com> May 15 2012
- Jonathan M Davis <jmdavisProg gmx.com> May 15 2012
- Walter Bright <newshound2 digitalmars.com> May 15 2012
- Timon Gehr <timon.gehr gmx.ch> May 16 2012
- Timon Gehr <timon.gehr gmx.ch> May 16 2012
- deadalnix <deadalnix gmail.com> May 16 2012
- Trass3r <un known.com> May 16 2012
- "Steven Schveighoffer" <schveiguy yahoo.com> May 16 2012
- Jacob Carlborg <doob me.com> May 16 2012
- "David Nadlinger" <see klickverbot.at> May 16 2012
- "Steven Schveighoffer" <schveiguy yahoo.com> May 16 2012
- "Mehrdad" <wfunction hotmail.com> May 16 2012
- "Mehrdad" <wfunction hotmail.com> May 16 2012
- "H. S. Teoh" <hsteoh quickfur.ath.cx> May 16 2012
- "Mehrdad" <wfunction hotmail.com> May 16 2012
- "H. S. Teoh" <hsteoh quickfur.ath.cx> May 16 2012
- "Jonathan M Davis" <jmdavisProg gmx.com> May 16 2012
- "H. S. Teoh" <hsteoh quickfur.ath.cx> May 16 2012
- Artur Skawina <art.08.09 gmail.com> May 16 2012
I'm writing some (low-level) code with no exception handling available whatsoever... either the code runs, or it doesn't. Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
May 15 2012
On Wednesday, May 16, 2012 05:54:04 Mehrdad wrote:I'm writing some (low-level) code with no exception handling available whatsoever... either the code runs, or it doesn't. Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; } So, you can use scope(exit) if the above code is acceptable for whatever you're doing. Otherwise, no, you can't. Destructors should work regardless of what you're doing with exceptions though, so I would expect RAII to work. - Jonathan M Davis
May 15 2012
On Wednesday, 16 May 2012 at 05:06:51 UTC, Jonathan M Davis wrote:scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; } So, you can use scope(exit) if the above code is acceptable for whatever you're doing. Otherwise, no, you can't.
Thanks, though I already knew that...Destructors should work regardless of what you're doing with exceptions though, so I would expect RAII to work.
Well, RAII is pretty much just a finally block... It seems like all of these emit references _d_local_unwind2 and stuff, so it seems like it's not the way you expect...
May 15 2012
On 5/15/2012 10:06 PM, Jonathan M Davis wrote:On Wednesday, May 16, 2012 05:54:04 Mehrdad wrote:I'm writing some (low-level) code with no exception handling available whatsoever... either the code runs, or it doesn't. Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; } So, you can use scope(exit) if the above code is acceptable for whatever you're doing. Otherwise, no, you can't. Destructors should work regardless of what you're doing with exceptions though, so I would expect RAII to work. - Jonathan M Davis
And if otherStuff is marked all nothrow, then the exception parts are pulled out. It's pretty much the entire point of having nothrow annotations.
May 15 2012
Le 16/05/2012 11:59, Trass3r a écrit :scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; }
pulled out. It's pretty much the entire point of having nothrow annotations.
This should be added to http://dlang.org/function.html#nothrow-functions
Except for thing throw by the runtime, which can basically occur at any moment.
May 16 2012
On 05/16/2012 11:09 PM, H. S. Teoh wrote:OK, this isn't the same as your nothrow wrapper, but the principle is the same. The funcWrap template can basically call _any_ function that returns _anything_. D just acquired whole new levels of cool for me. :-)
There are still some restrictions to be sorted out though. For example, try it with funcWrap(&printShort,1);
May 16 2012
On Wednesday, 16 May 2012 at 05:39:08 UTC, Brad Roberts wrote:On 5/15/2012 10:06 PM, Jonathan M Davis wrote:On Wednesday, May 16, 2012 05:54:04 Mehrdad wrote:I'm writing some (low-level) code with no exception handling available whatsoever... either the code runs, or it doesn't. Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; } So, you can use scope(exit) if the above code is acceptable for whatever you're doing. Otherwise, no, you can't. Destructors should work regardless of what you're doing with exceptions though, so I would expect RAII to work. - Jonathan M Davis
And if otherStuff is marked all nothrow, then the exception parts are pulled out. It's pretty much the entire point of having nothrow annotations.
Oooh, *that* I did not know. Very interesting, thanks for pointing that out!
May 15 2012
On Wednesday, 16 May 2012 at 05:46:03 UTC, Mehrdad wrote:=Oooh, *that* I did not know. Very interesting, thanks for pointing that out!
You could try scope(success), but the nothrow annotations sound like a better idea
May 15 2012
On Wednesday, May 16, 2012 07:30:44 Mehrdad wrote:Well, RAII is pretty much just a finally block... It seems like all of these emit references _d_local_unwind2 and stuff, so it seems like it's not the way you expect...
It all depends on how it's implemented I guess. RAII doesn't directly have anything to do with exceptions (though it's a good way to write exception-safe code), so it would be perfectly possible to have it in a language with no exceptions at all, but I guess that it could be implemented in a manner similar to finally blocks, much as I wouldn't have expected it. I haven't looked at what exactly the compiler generates though, so if you've dug into that, you know more about it than I do. - Jonathan M Davis
May 15 2012
On 5/15/2012 8:54 PM, Mehrdad wrote:Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
Make sure the guarded code is 'nothrow', and it should work.
May 15 2012
On 05/16/2012 08:59 AM, Walter Bright wrote:On 5/15/2012 8:54 PM, Mehrdad wrote:Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
Make sure the guarded code is 'nothrow', and it should work.
Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?
May 16 2012
On 05/16/2012 11:17 PM, Jonathan M Davis wrote:On Wednesday, May 16, 2012 23:05:07 Timon Gehr wrote:On 05/16/2012 08:59 AM, Walter Bright wrote:On 5/15/2012 8:54 PM, Mehrdad wrote:Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
Make sure the guarded code is 'nothrow', and it should work.
Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?
Well, according to Walter, there is no guarantee that _any_ cleanup will be done when an Error is thrown (including AssertError), so yes, there's the possibility that an in contract could leave the program in an invalid state if it fails.
The issue is not relevant for failing contracts. 'in' contracts might pass even if some assertion errors were thrown during their evaluation.However, with the current implementation, as I understand it, it _is_ guaranteed that cleanup will be done for Errors. But if the try and finally blocks are indeed removed, then that would seem to indicate that there's a case where there _won't_ be any cleaup for Errors in spite of the fact that Don (and and Dan?) tried to make sure that it _was_ guaranteed. But if the cleanup doesn't happen, it would still be within what Walter considers to be guarantee for Errors as far as the spec goes. - Jonathan M Davis
Exactly, this is somewhat bothersome.
May 16 2012
Le 16/05/2012 08:59, Walter Bright a écrit :On 5/15/2012 8:54 PM, Mehrdad wrote:Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
Make sure the guarded code is 'nothrow', and it should work.
It doesn't right now, and exceptions can be thrown at any time basically. scope(success) seems like a better choice here, but I'm not sure of the generated code for it.
May 16 2012
scope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; }
pulled out. It's pretty much the entire point of having nothrow annotations.
This should be added to http://dlang.org/function.html#nothrow-functions
May 16 2012
On Tue, 15 May 2012 23:54:04 -0400, Mehrdad <wfunction hotmail.com> wrote:I'm writing some (low-level) code with no exception handling available whatsoever... either the code runs, or it doesn't. Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
struct AddExitBlock { private void delegate() dg; this(scope void delegate() dg) {this.dg = dg;} ~this() {dg();} } void main() { int x = 0; { x = 1; immutable _aeb = AddExitBlock({x = 0;}); // annoying to have to assign it to a temporary variable, but whatever. assert(x == 1); } assert(x == 0); } Also seems to work with exceptions (if you need them): void foo(ref int x) { x = 1; immutable aeb1 = AddExitBlock({x = 0;}); throw new Exception("testing!"); } void main() { int x = 0; try { foo(x); } catch(Exception e) { } assert(x == 0); } I don't see exception handling in the generated code (at least I don't see the _d_local_unwind2), I wonder a) if this is more efficient than scope(exit), and b) if so, why can't the compiler do this automatically? -Steve
May 16 2012
On 2012-05-16 15:10, Steven Schveighoffer wrote:I don't see exception handling in the generated code (at least I don't see the _d_local_unwind2), I wonder a) if this is more efficient than scope(exit), and b) if so, why can't the compiler do this automatically?
I'm guessing because constructors and destructors hadn't been introduced for structs when the scope-statement was. -- /Jacob Carlborg
May 16 2012
On Wednesday, 16 May 2012 at 13:10:05 UTC, Steven Schveighoffer wrote:I don't see exception handling in the generated code (at least I don't see the _d_local_unwind2), I wonder a) if this is more efficient than scope(exit), and b) if so, why can't the compiler do this automatically?
I think you might be misreading the assembly – which operating system are you on? You can only expect to see _d_local_unwind on Windows, Dwarf EH is implemented differently. In the first case, where the code can't throw, the exception handling code is probably not generated at all. David
May 16 2012
On Wed, 16 May 2012 13:19:01 -0400, David Nadlinger <see klickverbot.at>= = wrote:On Wednesday, 16 May 2012 at 13:10:05 UTC, Steven Schveighoffer wrote:=
I don't see exception handling in the generated code (at least I don'=
see the _d_local_unwind2), I wonder a) if this is more efficient than=
scope(exit), and b) if so, why can't the compiler do this automatical=
I think you might be misreading the assembly =E2=80=93 which operating=
are you on? You can only expect to see _d_local_unwind on Windows, Dwa=
EH is implemented differently.
OK, that probably explains it :)In the first case, where the code can't throw, the exception handling =
code is probably not generated at all.
Yes, I see that the compiler likely does the right thing, and I just = implemented a totally useless feature in the face of scope(exit) :) I was kind of curious though, if it would work! -Steve
May 16 2012
Hmmm... when I remove the reference to SNN.lib, the code
auto scoped() nothrow {
struct S { ~this() { } }
S s;
return s;
}
void main() { auto s = scoped(); }
tells me
Error 42: Symbol Undefined __d_framehandler
Error 42: Symbol Undefined __except_list
But, when I change it to
auto scoped() nothrow {
struct S { ~this() { } }
return S();
}
it compiles fine.
Is this counted as a 'bug'? Or is it intentional? (Should I
report it?)
May 16 2012
Oh, and I just invented a most *lovely* cast: :P
auto noThrow(T)(scope T function() t) nothrow
{ return (cast(T function() nothrow)t)(); }
auto noThrow(T)(scope T delegate() t) nothrow
{ return (cast(T delegate() nothrow)t)(); }
May 16 2012
On Wed, May 16, 2012 at 10:41:06PM +0200, Mehrdad wrote:Oh, and I just invented a most *lovely* cast: :P auto noThrow(T)(scope T function() t) nothrow { return (cast(T function() nothrow)t)(); } auto noThrow(T)(scope T delegate() t) nothrow { return (cast(T delegate() nothrow)t)(); }
What about: auto noThrow(T,U...)(scope T function(U) t) nothrow { return (cast(T function(U) nothrow)t)(); } auto noThrow(T,U...)(scope T delegate(U) t) nothrow { return (cast(T delegate(U) nothrow)t)(); } ? (I've no idea if this actually works, but it does allow you to wrap almost _any_ function.) T -- Lawyer: (n.) An innocence-vending machine, the effectiveness of which depends on how much money is inserted.
May 16 2012
On Wednesday, 16 May 2012 at 20:48:27 UTC, H. S. Teoh wrote:What about: auto noThrow(T,U...)(scope T function(U) t) nothrow { return (cast(T function(U) nothrow)t)(); } auto noThrow(T,U...)(scope T delegate(U) t) nothrow { return (cast(T delegate(U) nothrow)t)(); } ? (I've no idea if this actually works, but it does allow you to wrap almost _any_ function.) T
Haha maybe, idk. I just wrote what I wrote so that I could use it like: noThrow({ // giant block of code }); to execute it as nothrow.
May 16 2012
On Wed, May 16, 2012 at 10:54:26PM +0200, Mehrdad wrote: [...]Haha maybe, idk. I just wrote what I wrote so that I could use it like: noThrow({ // giant block of code }); to execute it as nothrow.
Whoa, this code works: import std.math; import std.stdio; T funcWrap(T,U...)(scope T function(U) f, U args) { writeln("Calling wrapped function"); scope(exit) writeln("Wrapped function returned"); return f(args); } void printInt(int x) { writeln(x); } float computeFloat(float x, float y) { return x^^2 + y; } void main() { funcWrap(&printInt, 12345); writeln("Result is: ", funcWrap(&computeFloat, 3.0f, 1.5f)); funcWrap({ writeln("Inside an anonymous delegate"); }); funcWrap((int x) { writeln("Delegate with parameter: ", x); }, 100); } Output: Calling wrapped function 12345 Wrapped function returned Calling wrapped function Wrapped function returned Result is: 10.5 Calling wrapped function Inside an anonymous delegate Wrapped function returned Calling wrapped function Delegate with parameter: 100 Wrapped function returned OK, this isn't the same as your nothrow wrapper, but the principle is the same. The funcWrap template can basically call _any_ function that returns _anything_. D just acquired whole new levels of cool for me. :-) T -- ASCII stupid question, getty stupid ANSI.
May 16 2012
On Wednesday, May 16, 2012 23:05:07 Timon Gehr wrote:On 05/16/2012 08:59 AM, Walter Bright wrote:On 5/15/2012 8:54 PM, Mehrdad wrote:Is there any way for me to use scope(exit) (or perhaps a destructor, like RAII) to mean, "Execute this block of code for me when the block is exited, will ya?", *without* introducing dependencies on exception handling?
Make sure the guarded code is 'nothrow', and it should work.
Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?
Well, according to Walter, there is no guarantee that _any_ cleanup will be done when an Error is thrown (including AssertError), so yes, there's the possibility that an in contract could leave the program in an invalid state if it fails. However, with the current implementation, as I understand it, it _is_ guaranteed that cleanup will be done for Errors. But if the try and finally blocks are indeed removed, then that would seem to indicate that there's a case where there _won't_ be any cleaup for Errors in spite of the fact that Don (and and Dan?) tried to make sure that it _was_ guaranteed. But if the cleanup doesn't happen, it would still be within what Walter considers to be guarantee for Errors as far as the spec goes. - Jonathan M Davis
May 16 2012
On Wed, May 16, 2012 at 11:34:18PM +0200, Timon Gehr wrote:On 05/16/2012 11:09 PM, H. S. Teoh wrote:OK, this isn't the same as your nothrow wrapper, but the principle is the same. The funcWrap template can basically call _any_ function that returns _anything_. D just acquired whole new levels of cool for me. :-)
There are still some restrictions to be sorted out though. For example, try it with funcWrap(&printShort,1);
Yes I noticed that compiler type inference didn't work in that case. This is one area I really hope will be improved soon. I kept running into this in the new AA implementation: assigning [1,2,3] to ubyte[] works, but passing [1,2,3] to a template automatically forces it into int[] even though the template body then tries to assign it to a ubyte[], causing an error. Somebody mentioned recently the idea of an opCastFrom() (which is to opCast() as opBinaryRight() is to opBinary()) which may help here: if a struct/class declares opCastFrom(ubyte[]), then assigning [1,2,3] to the struct should cause the compiler to interpret the [1,2,3] as ubyte[] instead of int[]. T -- If Java had true garbage collection, most programs would delete themselves upon execution. -- Robert Sewell
May 16 2012
On 05/16/12 23:46, H. S. Teoh wrote:On Wed, May 16, 2012 at 11:34:18PM +0200, Timon Gehr wrote:On 05/16/2012 11:09 PM, H. S. Teoh wrote:OK, this isn't the same as your nothrow wrapper, but the principle is the same. The funcWrap template can basically call _any_ function that returns _anything_. D just acquired whole new levels of cool for me. :-)
There are still some restrictions to be sorted out though. For example, try it with funcWrap(&printShort,1);
Yes I noticed that compiler type inference didn't work in that case. This is one area I really hope will be improved soon. I kept running into this in the new AA implementation: assigning [1,2,3] to ubyte[] works, but passing [1,2,3] to a template automatically forces it into int[] even though the template body then tries to assign it to a ubyte[], causing an error.
http://d.puremagic.com/issues/show_bug.cgi?id=4953 I don't have dmd here, hence can't check, but it seems there's a chance it's already fixed. artur
May 16 2012









Jonathan M Davis <jmdavisProg gmx.com> 