digitalmars.D.learn - Custom default exception handler?
- Nick Sabalausky (7/7) Feb 10 2014 I don't suppose there's a way to change the default exception handler
- Adam D. Ruppe (6/8) Feb 10 2014 I'm pretty sure there used to be, but not anymore looking at the
- Nick Sabalausky (38/45) Feb 10 2014 I don't strictly *need* to. But if you're curious, here's the story:
- Adam D. Ruppe (23/26) Feb 11 2014 BTW the ()=> there is unnecessary; when there's no arguments, you
- Nick Sabalausky (2/12) Feb 11 2014 Oh yea, good point. That's not bad at all;
- bearophile (5/8) Feb 11 2014 Is it possible to use a lazy argument there? And isn't it better
- Adam D. Ruppe (4/6) Feb 11 2014 I think it depends on the task. To just wrap generic code though
- Jacob Carlborg (4/12) Feb 11 2014 Perhaps you can do something with core.runtime.Runtime.traceHandler.
- Sean Kelly (5/5) Feb 11 2014 Throw a static exception (maybe even derived directly from
- Nick Sabalausky (5/10) Feb 11 2014 Oh, interesting. Is this something that can be relied on long-term? Ie,
- Sean Kelly (8/12) Feb 11 2014 It's intentional, and was done to serve two purposes. The first
- Nick Sabalausky (5/6) Feb 11 2014 I assume then that throwing something directly derived from Throwable
- Sean Kelly (7/14) Feb 12 2014 Everything runs cleanup code right now, unless someone changed
- Nick Sabalausky (34/39) Feb 11 2014 Hmm, my custom toString isn't being executed. Am I doing something wrong...
- Sean Kelly (8/32) Feb 12 2014 It looks like this has changed, and the method that's called now
- Nick Sabalausky (11/17) Feb 12 2014 Hmm, that still isn't getting called for me either:
- Sean Kelly (5/15) Feb 12 2014 It should. I'm not entirely sure why it isn't working. For
- Nick Sabalausky (13/23) Feb 12 2014 Argh, there seems to be something wonky with the new RDMD in 2.065-b3
- Nick Sabalausky (3/7) Feb 13 2014 RDMD Regression Filed:
I don't suppose there's a way to change the default exception handler without using a modified druntime? I'm not seeing one in the docs, but I could have overlooked something. Replacing a druntime function at link-time wouldn't be ideal because then druntime's handler couldn't be called as a fallback, at least without maintaining a duplicate of druntime's handler and keeping it in sync with the version of druntime being used.
Feb 10 2014
On Tuesday, 11 February 2014 at 03:53:05 UTC, Nick Sabalausky wrote:I don't suppose there's a way to change the default exception handler without using a modified druntimeI'm pretty sure there used to be, but not anymore looking at the source. The d_run_main function has a hardcoded catch block. Why do you need to change the default though? Can't you just wrap your own main function in a big try/catch block?
Feb 10 2014
On 2/10/2014 10:57 PM, Adam D. Ruppe wrote:On Tuesday, 11 February 2014 at 03:53:05 UTC, Nick Sabalausky wrote:I don't strictly *need* to. But if you're curious, here's the story: I like to use a little custom exception (Fail) in shell script-like stuff to bail out and exit with a given error message in an exception-safe way. This is for expected failure conditions, not internal errors (so for example: "copy src.txt" -> "Error, no destination given!" or "File src.txt doesn't exist!", etc), so the stack trace is unnecessary noise and omitted. Only the message is printed, maybe with a common prefix like "mytool: ERROR: ...". This is arguably a slight abuse of the exception system, but in script-like stuff the exception performance doesn't really matter, and I find it does greatly simply the error logic of D-based scripts. Helps keep simple scripts simple. I'm sticking this Fail stuff into a little utility lib for simple script-like programs, and so, if possible, I'd *like* to instruct users to just do this: void main() { installFailHandler(); ... } instead of all this boilerplate: int main() { try { ...user code... } catch(Fail e) { writeln(e.msg); return 1; } return 0; } I'm sure I could also do something like this, but it's rather ugly: int main() { mixin(handleFail!(() => { ...user code... })); } So not a real big deal, but it'd be nice if I could swing it.I don't suppose there's a way to change the default exception handler without using a modified druntimeI'm pretty sure there used to be, but not anymore looking at the source. The d_run_main function has a hardcoded catch block. Why do you need to change the default though? Can't you just wrap your own main function in a big try/catch block?
Feb 10 2014
On Tuesday, 11 February 2014 at 05:09:13 UTC, Nick Sabalausky wrote:mixin(handleFail!(() => { ...user code... }));BTW the ()=> there is unnecessary; when there's no arguments, you can just write { code } and it will be recognized as a function/delegate. So this would work too: int handleError(void delegate() dg) { try dg(); catch(Throwable t) return 1; return 0; } int main() { return handleError({ }); } (or of course, handleError(alias dg)() works too if you add the !). Still perhaps a bit wordier than installing the handler but I don't think it is too bad. You could also do something like i do in my cgi.d: void mymain() { code ... } mixin HandleError!mymain; // HandleError is a mixin tempalte that provides main(), does arg/exception handling, and returns the right value
Feb 11 2014
On 2/11/2014 10:00 AM, Adam D. Ruppe wrote:So this would work too: int handleError(void delegate() dg) { try dg(); catch(Throwable t) return 1; return 0; } int main() { return handleError({ }); }Oh yea, good point. That's not bad at all;
Feb 11 2014
Adam D. Ruppe:int handleError(void delegate() dg) { try dg(); catch(Throwable t) return 1;Is it possible to use a lazy argument there? And isn't it better to catch Exception only? Bye, bearophile
Feb 11 2014
On Wednesday, 12 February 2014 at 01:08:42 UTC, bearophile wrote:Is it possible to use a lazy argument there?I think it depends on the task. To just wrap generic code though a delegate seems most straightforward.And isn't it better to catch Exception only?Perhaps, or the specific FailException type or whatever.
Feb 11 2014
On 2014-02-11 06:09, Nick Sabalausky wrote:I don't strictly *need* to. But if you're curious, here's the story: I like to use a little custom exception (Fail) in shell script-like stuff to bail out and exit with a given error message in an exception-safe way. This is for expected failure conditions, not internal errors (so for example: "copy src.txt" -> "Error, no destination given!" or "File src.txt doesn't exist!", etc), so the stack trace is unnecessary noise and omitted. Only the message is printed, maybe with a common prefix like "mytool: ERROR: ...".Perhaps you can do something with core.runtime.Runtime.traceHandler. -- /Jacob Carlborg
Feb 11 2014
Throw a static exception (maybe even derived directly from Throwable), similar to OutOfMemory, with a custom toString. That should eliminate the formatting you don't like and will prevent the trace from occurring as well (see rt/deh.d in Druntime--the trace isn't run if you throw typeid(t).init.ptr).
Feb 11 2014
On 2/11/2014 6:35 PM, Sean Kelly wrote:Throw a static exception (maybe even derived directly from Throwable), similar to OutOfMemory, with a custom toString. That should eliminate the formatting you don't like and will prevent the trace from occurring as well (see rt/deh.d in Druntime--the trace isn't run if you throw typeid(t).init.ptr).Oh, interesting. Is this something that can be relied on long-term? Ie, is a static non-Exception Throwable deliberately *supposed* to not include a stack trace, or is it potentially more of a currently-missing feature?
Feb 11 2014
On Wednesday, 12 February 2014 at 01:07:31 UTC, Nick Sabalausky wrote:Oh, interesting. Is this something that can be relied on long-term? Ie, is a static non-Exception Throwable deliberately *supposed* to not include a stack trace, or is it potentially more of a currently-missing feature?It's intentional, and was done to serve two purposes. The first was to provide some way for throwing OutOfMemory to not accidentally try to allocate, and the second was because if you throw the same static instance in two threads simultaneously, the trace would end up invalid for one of them. The only safe thing to do is not trace at all.
Feb 11 2014
On 2/11/2014 6:35 PM, Sean Kelly wrote:Throw a static exception (maybe even derived directly from Throwable),I assume then that throwing something directly derived from Throwable would still run cleanup code (like scope guards and finally) like throwing Exception would? Or is it like throwing an Error, skipping cleanup code?
Feb 11 2014
On Wednesday, 12 February 2014 at 02:41:34 UTC, Nick Sabalausky wrote:On 2/11/2014 6:35 PM, Sean Kelly wrote:Everything runs cleanup code right now, unless someone changed things on me. But if a change were made, I'd say that only Error and its children would skip cleanup. The default would be to perform cleanup. That lets users create their own exception hierarchies.Throw a static exception (maybe even derived directly from Throwable),I assume then that throwing something directly derived from Throwable would still run cleanup code (like scope guards and finally) like throwing Exception would? Or is it like throwing an Error, skipping cleanup code?
Feb 12 2014
On 2/11/2014 6:35 PM, Sean Kelly wrote:Throw a static exception (maybe even derived directly from Throwable), similar to OutOfMemory, with a custom toString. That should eliminate the formatting you don't like and will prevent the trace from occurring as well (see rt/deh.d in Druntime--the trace isn't run if you throw typeid(t).init.ptr).Hmm, my custom toString isn't being executed. Am I doing something wrong here? Same result if I inherit direct from Throwable instead of Exception. class Fail : Exception { private this() { super(null); } private static Fail opCall(string msg, string file=__FILE__, int line=__LINE__) { auto f = cast(Fail) cast(void*) Fail.classinfo.init; f.msg = msg; f.file = file; f.line = line; return f; } override string toString() { writeln("In Fail.toString()"); return "someapp: ERROR: "~msg; } } void fail(string msg, string file=__FILE__, int line=__LINE__) { throw Fail(msg, file, line); } void main() { fail("Shit/fan collision detected."); } Output: scriptlike.Fail scriptlike.d(106): Shit/fan collision detected.
Feb 11 2014
On Wednesday, 12 February 2014 at 03:31:38 UTC, Nick Sabalausky wrote:Hmm, my custom toString isn't being executed. Am I doing something wrong here? Same result if I inherit direct from Throwable instead of Exception. class Fail : Exception { private this() { super(null); } private static Fail opCall(string msg, string file=__FILE__, int line=__LINE__) { auto f = cast(Fail) cast(void*) Fail.classinfo.init; f.msg = msg; f.file = file; f.line = line; return f; } override string toString() { writeln("In Fail.toString()"); return "someapp: ERROR: "~msg; } }It looks like this has changed, and the method that's called now is: void toString(scope void delegate(in char[]) sink) const; I suspect this has broken a lot of custom exception messages, since everything in core.exception still uses toString() for its output.
Feb 12 2014
On 2/12/2014 4:14 PM, Sean Kelly wrote:It looks like this has changed, and the method that's called now is: void toString(scope void delegate(in char[]) sink) const; I suspect this has broken a lot of custom exception messages, since everything in core.exception still uses toString() for its output.Hmm, that still isn't getting called for me either: void toString(scope void delegate(in char[]) sink) const { import std.stdio; writeln("In Fail.toString()"); sink("someapp: ERROR: "~msg); } Tried on both 2.064.2 and 2.065-b3. Could it be that the custom toString just doesn't get run for static exceptions?
Feb 12 2014
On Wednesday, 12 February 2014 at 22:42:45 UTC, Nick Sabalausky wrote:Hmm, that still isn't getting called for me either: void toString(scope void delegate(in char[]) sink) const { import std.stdio; writeln("In Fail.toString()"); sink("someapp: ERROR: "~msg); } Tried on both 2.064.2 and 2.065-b3. Could it be that the custom toString just doesn't get run for static exceptions?It should. I'm not entirely sure why it isn't working. For reference, the relevant code is in rt/dmain2.d (printThrowable) and object_.d (toString(sink)) in Druntime.
Feb 12 2014
On 2/12/2014 6:14 PM, Sean Kelly wrote:On Wednesday, 12 February 2014 at 22:42:45 UTC, Nick Sabalausky wrote:Argh, there seems to be something wonky with the new RDMD in 2.065-b3 (or hopefully it's just my system): If I use the RDMD from 2.064.2 to invoke DMD 2.065-b3 then this all works fine (thanks!). But if I use the RDMD/DMD *both* from DMD 2.065-b3 then...I dunno, either the exe doesn't get actually get rebuilt even with --force, or maybe it does but then runs an older copy of the exe, or something screwy like that. I need to look into that more. Looks like it's *not* going to work with DMD 2.064.2 though. In that version, printThrowable never actually calls Throwable.toString (*any* version of toString for that matter), and the sink version of Throwable.toString doesn't even exist. That's fine though, at least I know it'll work staring with 2.065.Tried on both 2.064.2 and 2.065-b3. Could it be that the custom toString just doesn't get run for static exceptions?It should. I'm not entirely sure why it isn't working. For reference, the relevant code is in rt/dmain2.d (printThrowable) and object_.d (toString(sink)) in Druntime.
Feb 12 2014
On 2/13/2014 2:55 AM, Nick Sabalausky wrote:But if I use the RDMD/DMD *both* from DMD 2.065-b3 then...I dunno, either the exe doesn't get actually get rebuilt even with --force, or maybe it does but then runs an older copy of the exe, or something screwy like that. I need to look into that more.RDMD Regression Filed: https://d.puremagic.com/issues/show_bug.cgi?id=12149
Feb 13 2014