digitalmars.D - scope(exit) without exception handling?
- Mehrdad (6/6) May 15 2012 I'm writing some (low-level) code with no exception handling
- Jonathan M Davis (17/24) May 15 2012 scope(exit) stuff;
- Mehrdad (5/20) May 15 2012 Well, RAII is pretty much just a finally block...
- Jonathan M Davis (9/12) May 15 2012 It all depends on how it's implemented I guess. RAII doesn't directly ha...
- Brad Roberts (3/33) May 15 2012 And if otherStuff is marked all nothrow, then the exception parts are pu...
- Mehrdad (3/38) May 15 2012 Oooh, *that* I did not know. Very interesting, thanks for
- Robert DaSilva (3/5) May 15 2012 You could try scope(success), but the nothrow annotations sound
- Trass3r (2/19) May 16 2012 This should be added to
- deadalnix (3/22) May 16 2012 Except for thing throw by the runtime, which can basically occur at any
- Mehrdad (18/18) May 16 2012 Hmmm... when I remove the reference to SNN.lib, the code
- Mehrdad (5/5) May 16 2012 Oh, and I just invented a most *lovely* cast: :P
- H. S. Teoh (15/22) May 16 2012 What about:
- Mehrdad (7/19) May 16 2012 Haha maybe, idk. I just wrote what I wrote so that I could use it
- H. S. Teoh (47/56) May 16 2012 Whoa, this code works:
- Timon Gehr (3/7) May 16 2012 There are still some restrictions to be sorted out though. For example,
- H. S. Teoh (15/26) May 16 2012 Yes I noticed that compiler type inference didn't work in that case.
- Artur Skawina (5/24) May 16 2012 http://d.puremagic.com/issues/show_bug.cgi?id=4953
- Walter Bright (2/5) May 15 2012 Make sure the guarded code is 'nothrow', and it should work.
- Timon Gehr (3/10) May 16 2012 Doesn't that imply that 'in'-contract checking might leave the program
- Jonathan M Davis (12/24) May 16 2012 Well, according to Walter, there is no guarantee that _any_ cleanup will...
- Timon Gehr (4/29) May 16 2012 The issue is not relevant for failing contracts. 'in' contracts might
- deadalnix (4/11) May 16 2012 It doesn't right now, and exceptions can be thrown at any time basically...
- Steven Schveighoffer (41/47) May 16 2012 struct AddExitBlock
- Jacob Carlborg (5/8) May 16 2012 I'm guessing because constructors and destructors hadn't been introduced...
- David Nadlinger (8/12) May 16 2012 I think you might be misreading the assembly – which operating
-
Steven Schveighoffer
(14/23)
May 16 2012
On Wed, 16 May 2012 13:19:01 -0400, David Nadlinger
...
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 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 10:06 PM, Jonathan M Davis wrote:On Wednesday, May 16, 2012 05:54:04 Mehrdad wrote: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.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:39:08 UTC, Brad Roberts wrote:On 5/15/2012 10:06 PM, Jonathan M Davis wrote:Oooh, *that* I did not know. Very interesting, thanks for pointing that out!On Wednesday, May 16, 2012 05:54:04 Mehrdad wrote: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.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: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
This should be added to http://dlang.org/function.html#nothrow-functionsscope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; }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 16 2012
Le 16/05/2012 11:59, Trass3r a écrit :Except for thing throw by the runtime, which can basically occur at any moment.This should be added to http://dlang.org/function.html#nothrow-functionsscope(exit) stuff; otherStuff; is lowered to something like try { otherStuff; } finally { stuff; }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 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.) THaha 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 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 Wed, May 16, 2012 at 11:34:18PM +0200, Timon Gehr wrote:On 05/16/2012 11:09 PM, H. S. Teoh wrote: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 SewellOK, 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 05/16/12 23:46, H. S. Teoh wrote:On Wed, May 16, 2012 at 11:34:18PM +0200, Timon Gehr wrote: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. arturOn 05/16/2012 11:09 PM, H. S. Teoh wrote: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.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 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:Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?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 16 2012
On Wednesday, May 16, 2012 23:05:07 Timon Gehr wrote:On 05/16/2012 08:59 AM, Walter Bright wrote: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 DavisOn 5/15/2012 8:54 PM, Mehrdad wrote:Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?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 16 2012
On 05/16/2012 11:17 PM, Jonathan M Davis wrote:On Wednesday, May 16, 2012 23:05:07 Timon Gehr wrote:The issue is not relevant for failing contracts. 'in' contracts might pass even if some assertion errors were thrown during their evaluation.On 05/16/2012 08:59 AM, Walter Bright wrote: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.On 5/15/2012 8:54 PM, Mehrdad wrote:Doesn't that imply that 'in'-contract checking might leave the program in an invalid state?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.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 DavisExactly, 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: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.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 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:=t =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=ly?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=system =are you on? You can only expect to see _d_local_unwind on Windows, Dwa=rf =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