digitalmars.D - Throwable class design
- rumbu (7/7) Jan 29 2013 I have one question regarding the Throwable, Error and Exception
- H. S. Teoh (10/18) Jan 29 2013 Not true. I use this idiom a lot: a lower level function throws an error
- Mehrdad (3/10) Jan 29 2013 Shouldn't you be throwing a new exception, with the old exception
- rumbu (13/25) Jan 29 2013 I thought exceptions are meant to be catched, not rethrown.
- Jonathan M Davis (10/40) Jan 30 2013 Exceptions get rethrown all the time. Heck, that's what happens with fin...
- rumbu (7/22) Jan 30 2013 Exceptions are not rethrown, finally block is executed *after*
- simendsjo (13/38) Jan 30 2013 Finally needs to rethrow the exception at the end of the scope.
- Jonathan M Davis (20/46) Jan 30 2013 You seem to think that rethrowing has something to do with mutation. It
- H. S. Teoh (30/66) Jan 30 2013 The point is that an error has occurred, and normal processing cannot
- rumbu (11/11) Jan 30 2013 Ok, maybe my thoughts are polluted by some C# programming
- H. S. Teoh (26/37) Jan 30 2013 Maybe that is accepted convention in the Windows world, but I consider
- Jonathan M Davis (10/27) Jan 30 2013 I would never show an exception to a user, even in Linux. I might show t...
- simendsjo (6/53) Jan 30 2013 I would much rather show a stacktrace to the user than "Unknown
- Kagamin (2/4) Jan 31 2013 These two approaches do not conflict and Windows solves the
- H. S. Teoh (10/39) Jan 30 2013 [...]
- Sean Kelly (9/12) Jan 31 2013 not hidden behind read-only properties or functions. What was the reason...
- Andrej Mitrovic (21/25) Jan 31 2013 I'd rather we not, it's useful being able to modify msg and line
- H. S. Teoh (7/36) Jan 31 2013 +1. Like this idea, I'll have to start using it to avoid the headache of
- rumbu (9/50) Jan 31 2013 I found this approach wrong, FormatException already contains
- Andrej Mitrovic (5/8) Jan 31 2013 Self pro-tip: Wrap it in a template so you can do:
- Andrej Mitrovic (39/40) Jan 31 2013 Here, and I didn't even have to use string mixins:
- Jonathan M Davis (4/8) Jan 31 2013 Just remember that that means that you'll get a new template instantiati...
I have one question regarding the Throwable, Error and Exception classes. I cannot understand why members like msg, file, line, info or next are not hidden behind read-only properties or functions. What was the reason behind making these fields public? As far as I know, once an exception is thrown, there is no interest in modifying contained members.
Jan 29 2013
On Wed, Jan 30, 2013 at 07:49:37AM +0100, rumbu wrote:I have one question regarding the Throwable, Error and Exception classes. I cannot understand why members like msg, file, line, info or next are not hidden behind read-only properties or functions. What was the reason behind making these fields public? As far as I know, once an exception is thrown, there is no interest in modifying contained members.Not true. I use this idiom a lot: a lower level function throws an error message (e.g., integer format error), and a catch-block halfway up the call-chain modifies .msg to include contextual information (e.g., filename, line number) and rethrows the exception, so that at the top level the error message contains both context information and the low-level error message. T -- The peace of mind---from knowing that viruses which exploit Microsoft system vulnerabilities cannot touch Linux---is priceless. -- Frustrated system administrator.
Jan 29 2013
On Wednesday, 30 January 2013 at 07:01:56 UTC, H. S. Teoh wrote:Not true. I use this idiom a lot: a lower level function throws an error message (e.g., integer format error), and a catch-block halfway up the call-chain modifies .msg to include contextual information (e.g., filename, line number) and rethrows the exception, so that at the top level the error message contains both context information and the low-level error message.Shouldn't you be throwing a new exception, with the old exception wrapped inside?
Jan 29 2013
On Wednesday, 30 January 2013 at 07:01:56 UTC, H. S. Teoh wrote:Not true. I use this idiom a lot: a lower level function throws an error message (e.g., integer format error), and a catch-block halfway up the call-chain modifies .msg to include contextual information (e.g., filename, line number) and rethrows the exception, so that at the top level the error message contains both context information and the low-level error message. TI thought exceptions are meant to be catched, not rethrown. If you are the developper of an end user solution, you'll catch the exception and you will display a message some way with the details that you need, or, better, you will silently drop the exception taking the necessary actions to resolve the cause. Throwing exceptions in the user's face is not so friendly. If you are a library developper, you'll catch the exception and you will rethrow *another* exception wrapping the original exception in the next field through the constructor. Target developpers of your library have no interest in your detailed message, but in the *type* of the exception thrown. Their program flow cannot interpret messages.
Jan 29 2013
On Wednesday, January 30, 2013 08:32:47 rumbu wrote:On Wednesday, 30 January 2013 at 07:01:56 UTC, H. S. Teoh wrote:Exceptions get rethrown all the time. Heck, that's what happens with finally, scope(failure), and scope(exit). It's what you do when you need to react to the fact that the exception was thrown (maybe even to the specific exception) but aren't going to handle it in that section of code. Now, mutating the exception before rethrowing is another thing. I'd tend to think that that was bad practice, but I suppose that it could be useful upon occasion. In general though, if I wanted to add information, I'd wrap the caught exception in a new exception and throw that. - Jonathan M DavisNot true. I use this idiom a lot: a lower level function throws an error message (e.g., integer format error), and a catch-block halfway up the call-chain modifies .msg to include contextual information (e.g., filename, line number) and rethrows the exception, so that at the top level the error message contains both context information and the low-level error message. TI thought exceptions are meant to be catched, not rethrown. If you are the developper of an end user solution, you'll catch the exception and you will display a message some way with the details that you need, or, better, you will silently drop the exception taking the necessary actions to resolve the cause. Throwing exceptions in the user's face is not so friendly. If you are a library developper, you'll catch the exception and you will rethrow *another* exception wrapping the original exception in the next field through the constructor. Target developpers of your library have no interest in your detailed message, but in the *type* of the exception thrown. Their program flow cannot interpret messages.
Jan 30 2013
On Wednesday, 30 January 2013 at 08:44:52 UTC, Jonathan M Davis wrote:Exceptions get rethrown all the time. Heck, that's what happens with finally, scope(failure), and scope(exit). It's what you do when you need to react to the fact that the exception was thrown (maybe even to the specific exception) but aren't going to handle it in that section of code. Now, mutating the exception before rethrowing is another thing. I'd tend to think that that was bad practice, but I suppose that it could be useful upon occasion. In general though, if I wanted to add information, I'd wrap the caught exception in a new exception and throw that. - Jonathan M DavisExceptions are not rethrown, finally block is executed *after* throwing/catching the exception. I don't know the details of the scope(*) implementations, but I doubt that they are rethrowing any exceptions. Exceptions are propagated, not rethrown with a mutated message or field.
Jan 30 2013
On Wednesday, 30 January 2013 at 09:05:22 UTC, rumbu wrote:On Wednesday, 30 January 2013 at 08:44:52 UTC, Jonathan M Davis wrote:Finally needs to rethrow the exception at the end of the scope. If an exception is thrown in the finally clause, it is chained at the end of the exception currently in flight. I'm pretty sure scope(*) just lowers to try/catch/finally: try { // something // scope(success) } catch (Exception) { // scope(failure) } finally { // scope(exit) }Exceptions get rethrown all the time. Heck, that's what happens with finally, scope(failure), and scope(exit). It's what you do when you need to react to the fact that the exception was thrown (maybe even to the specific exception) but aren't going to handle it in that section of code. Now, mutating the exception before rethrowing is another thing. I'd tend to think that that was bad practice, but I suppose that it could be useful upon occasion. In general though, if I wanted to add information, I'd wrap the caught exception in a new exception and throw that. - Jonathan M DavisExceptions are not rethrown, finally block is executed *after* throwing/catching the exception. I don't know the details of the scope(*) implementations, but I doubt that they are rethrowing any exceptions. Exceptions are propagated, not rethrown with a mutated message or field.
Jan 30 2013
On Wednesday, January 30, 2013 10:05:21 rumbu wrote:On Wednesday, 30 January 2013 at 08:44:52 UTC, Jonathan M Davis wrote:You seem to think that rethrowing has something to do with mutation. It doesn't. Finally, scope(failure), and scope(exit) all must catch exceptions, run the code within their blocks, and then rethrow the exception. No mutation of the exception is involved. If they didn't rethrow the exception, then it would stop there and never escape those blocks, and if it weren't caught by them, then those blocks wouldn't be executed at all. Also I could easily do something like try throw new Exception("hello"); catch(Exception e) { writefln("It says: %s", e.msg); throw e; } I catch and use the exception and then rethrow it, but I don't mutate it. Yes, you can catch an exception, mutate it, and then rethrow it. But the fact that it's rethrown says nothing about whether it was mutated. It just means that the exception continues to propagate up again after it was caught. - Jonathan M DavisExceptions get rethrown all the time. Heck, that's what happens with finally, scope(failure), and scope(exit). It's what you do when you need to react to the fact that the exception was thrown (maybe even to the specific exception) but aren't going to handle it in that section of code. Now, mutating the exception before rethrowing is another thing. I'd tend to think that that was bad practice, but I suppose that it could be useful upon occasion. In general though, if I wanted to add information, I'd wrap the caught exception in a new exception and throw that. - Jonathan M DavisExceptions are not rethrown, finally block is executed *after* throwing/catching the exception. I don't know the details of the scope(*) implementations, but I doubt that they are rethrowing any exceptions. Exceptions are propagated, not rethrown with a mutated message or field.
Jan 30 2013
On Wed, Jan 30, 2013 at 12:43:49AM -0800, Jonathan M Davis wrote:On Wednesday, January 30, 2013 08:32:47 rumbu wrote:The point is that an error has occurred, and normal processing cannot continue, so an exception is thrown. The catching here is not to throw an exception "at the user's face"; it is to insert additional information about the problem at an intermediate level up the call-chain. Further up the call chain, the application would still catch the exception and display the message. The rationale for modifying the exception message is that (1) the low-level code that threw the original exception does not have enough context to be able to provide a helpful message (e.g., it doesn't directly know which filename/line number it's processing, it's just a low-level dumb conversion routine), and (2) a little further up the call chain are functions that *do* have enough context to insert helpful information, so they catch the exception, add on the context information, and rethrow the exception to continue propagating the error condition. This way, you will get to see both the exact problem that caused the processing to fail (the original .msg) and also where in the input (filename/line number) that triggered this problem.On Wednesday, 30 January 2013 at 07:01:56 UTC, H. S. Teoh wrote:Not true. I use this idiom a lot: a lower level function throws an error message (e.g., integer format error), and a catch-block halfway up the call-chain modifies .msg to include contextual information (e.g., filename, line number) and rethrows the exception, so that at the top level the error message contains both context information and the low-level error message. TI thought exceptions are meant to be catched, not rethrown. If you are the developper of an end user solution, you'll catch the exception and you will display a message some way with the details that you need, or, better, you will silently drop the exception taking the necessary actions to resolve the cause. Throwing exceptions in the user's face is not so friendly.The message is intended for the end-user, not the library code.If you are a library developper, you'll catch the exception and you will rethrow *another* exception wrapping the original exception in the next field through the constructor. Target developpers of your library have no interest in your detailed message, but in the *type* of the exception thrown. Their program flow cannot interpret messages.Exceptions get rethrown all the time. Heck, that's what happens with finally, scope(failure), and scope(exit). It's what you do when you need to react to the fact that the exception was thrown (maybe even to the specific exception) but aren't going to handle it in that section of code. Now, mutating the exception before rethrowing is another thing. I'd tend to think that that was bad practice, but I suppose that it could be useful upon occasion. In general though, if I wanted to add information, I'd wrap the caught exception in a new exception and throw that.[...] In my case, I guess I didn't really see the need to invent another wrapper exception type just to be able to insert filename/line number information. As far as the application code is concerned, a parsing error is a parsing error; it shouldn't need to know if said parsing error is a wrapper class containing the real exception object. All it cares to know is, a problem occurred, and the .msg field contains a description of the problem that can be displayed to the user. T -- Windows: the ultimate triumph of marketing over technology. -- Adrian von Bidder
Jan 30 2013
practices, but I learnt that exceptions are never intended for the end user (one of the reasons is that the exception mesages are in most cases displayed in english language). In Windows world, throwing an exception displays a message with a nice two buttons: Close and Debug. This will make the accountant using my software very eager to click on Debug :) My way to deal now with *unattended* exceptions is to log them for further investigation, but I will never display a raw exception message, considering the fact that my LOB applications are in most cases multilanguage.
Jan 30 2013
On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:but I learnt that exceptions are never intended for the end user (one of the reasons is that the exception mesages are in most cases displayed in english language). In Windows world, throwing an exception displays a message with a nice two buttons: Close and Debug. This will make the accountant using my software very eager to click on Debug :)Maybe that is accepted convention in the Windows world, but I consider exceptions as an excellent way of conveying what went wrong to the user. Such as "could not calculate cell value, expecting number in cell A5 but got 'adfsdfas' instead". Throwing an exception is the cleanest way to abort potentially deeply-nested calculation code and give the user a useful message in the meantime. I would hate to manually propagate such user errors by hand, just because of the convention that exception messages should never be seen by the user! OTOH, I do understand that *some* exceptions aren't intended for user consumption, such as internal errors in the program that are useful only to the programmer. In such cases, I would use separate branches of the exception class hierarchy, one for user-consumable exceptions, one for exceptions that should only be logged and replaced with a generic message (like "The application has encountered an internal problem, please report the problem to technical support". Though honestly, I can never stand these sorts of messages... but I do know some people prefer that than to seeing raw exception messages).My way to deal now with *unattended* exceptions is to log them for further investigation, but I will never display a raw exception message, considering the fact that my LOB applications are in most cases multilanguage.I guess it depends on the application, but you could always use i18n-keyed string in your exception messages instead of plain English. (Or use a gettext-like system where the English string is the key to the translation files.) Then you can translate the message before displaying it to the user. T -- "Real programmers can write assembly code in any language. :-)" -- Larry Wall
Jan 30 2013
On Wednesday, January 30, 2013 12:40:26 H. S. Teoh wrote:On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:I would never show an exception to a user, even in Linux. I might show the exception's message, but I would never let the exception escape and end up showing the stack trace and whatnot to the user. I see no problem in showing an exception's message to a user if that's what it was intended for. The fact that it was an exception which delivered the message is an implementation detail that the user doesn't care about and shouldn't know. But I suspect that the two of you pretty much agree about that but are thinking of different things when you're talking about "showing the exception to the user." - Jonathan M Davisbut I learnt that exceptions are never intended for the end user (one of the reasons is that the exception mesages are in most cases displayed in english language). In Windows world, throwing an exception displays a message with a nice two buttons: Close and Debug. This will make the accountant using my software very eager to click on Debug :)Maybe that is accepted convention in the Windows world, but I consider exceptions as an excellent way of conveying what went wrong to the user. Such as "could not calculate cell value, expecting number in cell A5 but got 'adfsdfas' instead". Throwing an exception is the cleanest way to abort potentially deeply-nested calculation code and give the user a useful message in the meantime. I would hate to manually propagate such user errors by hand, just because of the convention that exception messages should never be seen by the user!
Jan 30 2013
On Wednesday, 30 January 2013 at 21:07:41 UTC, Jonathan M Davis wrote:On Wednesday, January 30, 2013 12:40:26 H. S. Teoh wrote:I would much rather show a stacktrace to the user than "Unknown error" or some other little usable message. When a user copy/paste a stacktrace for a hard-to-reproduce problem, it's a *lot* simpler to fix the error or give a custom error message.On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:I would never show an exception to a user, even in Linux. I might show the exception's message, but I would never let the exception escape and end up showing the stack trace and whatnot to the user. I see no problem in showing an exception's message to a user if that's what it was intended for. The fact that it was an exception which delivered the message is an implementation detail that the user doesn't care about and shouldn't know. But I suspect that the two of you pretty much agree about that but are thinking of different things when you're talking about "showing the exception to the user." - Jonathan M Davispractices, but I learnt that exceptions are never intended for the end user (one of the reasons is that the exception mesages are in most cases displayed in english language). In Windows world, throwing an exception displays a message with a nice two buttons: Close and Debug. This will make the accountant using my software very eager to click on Debug :)Maybe that is accepted convention in the Windows world, but I consider exceptions as an excellent way of conveying what went wrong to the user. Such as "could not calculate cell value, expecting number in cell A5 but got 'adfsdfas' instead". Throwing an exception is the cleanest way to abort potentially deeply-nested calculation code and give the user a useful message in the meantime. I would hate to manually propagate such user errors by hand, just because of the convention that exception messages should never be seen by the user!
Jan 30 2013
I would much rather show a stacktrace to the user than "Unknown error" or some other little usable message.These two approaches do not conflict and Windows solves the problem by combining them since... Windows 2000, I guess.
Jan 31 2013
On Wed, Jan 30, 2013 at 04:07:31PM -0500, Jonathan M Davis wrote:On Wednesday, January 30, 2013 12:40:26 H. S. Teoh wrote:[...] Ah, the hilarity of English ambiguity... I meant "display the exception message", of course. Uncaught exceptions with stack traces in any application are Very Bad(tm). T -- Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. KernighanOn Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:I would never show an exception to a user, even in Linux. I might show the exception's message, but I would never let the exception escape and end up showing the stack trace and whatnot to the user. I see no problem in showing an exception's message to a user if that's what it was intended for. The fact that it was an exception which delivered the message is an implementation detail that the user doesn't care about and shouldn't know. But I suspect that the two of you pretty much agree about that but are thinking of different things when you're talking about "showing the exception to the user."practices, but I learnt that exceptions are never intended for the end user (one of the reasons is that the exception mesages are in most cases displayed in english language). In Windows world, throwing an exception displays a message with a nice two buttons: Close and Debug. This will make the accountant using my software very eager to click on Debug :)Maybe that is accepted convention in the Windows world, but I consider exceptions as an excellent way of conveying what went wrong to the user. Such as "could not calculate cell value, expecting number in cell A5 but got 'adfsdfas' instead". Throwing an exception is the cleanest way to abort potentially deeply-nested calculation code and give the user a useful message in the meantime. I would hate to manually propagate such user errors by hand, just because of the convention that exception messages should never be seen by the user!
Jan 30 2013
On Jan 29, 2013, at 10:49 PM, rumbu <rumbu rumbu.ro> wrote:I have one question regarding the Throwable, Error and Exception =classes.=20 I cannot understand why members like msg, file, line, info or next are =not hidden behind read-only properties or functions. What was the reason = behind making these fields public? As far as I know, once an exception = is thrown, there is no interest in modifying contained members. I think the reason is mostly historic--the original exception classes = had public members. There's no reason why they couldn't be hidden = behind read-only properties though, other than the potential to break = existing code.=
Jan 31 2013
On 2/1/13, Sean Kelly <sean invisibleduck.org> wrote:I think the reason is mostly historic--the original exception classes had public members. There's no reason why they couldn't be hidden behind read-only properties though, other than the potential to break existing code.I'd rather we not, it's useful being able to modify msg and line sometimes, e.g.: http://forum.dlang.org/thread/uudharkmihxjymsxcyxq forum.dlang.org#post-mailman.855.1359491827.22503.digitalmars-d-learn:40puremagic.com Another example, wrapping `format` to inject the local file and line: string fmt(string file = __FILE__, size_t line = __LINE__, Args...)(string fmtStr, Args args) { try { return format(fmtStr, args); } catch (FormatException exc) { exc.file = file; exc.line = line; throw exc; } } Saves me from having to read a broken stack trace or file and line within Phobos.
Jan 31 2013
On Fri, Feb 01, 2013 at 01:47:35AM +0100, Andrej Mitrovic wrote:On 2/1/13, Sean Kelly <sean invisibleduck.org> wrote:+1. Like this idea, I'll have to start using it to avoid the headache of trying to figure out where something blew up when the stacktrace points to some deep obscure code inside Phobos. T -- People tell me that I'm skeptical, but I don't believe it.I think the reason is mostly historic--the original exception classes had public members. There's no reason why they couldn't be hidden behind read-only properties though, other than the potential to break existing code.I'd rather we not, it's useful being able to modify msg and line sometimes, e.g.: http://forum.dlang.org/thread/uudharkmihxjymsxcyxq forum.dlang.org#post-mailman.855.1359491827.22503.digitalmars-d-learn:40puremagic.com Another example, wrapping `format` to inject the local file and line: string fmt(string file = __FILE__, size_t line = __LINE__, Args...)(string fmtStr, Args args) { try { return format(fmtStr, args); } catch (FormatException exc) { exc.file = file; exc.line = line; throw exc; } } Saves me from having to read a broken stack trace or file and line within Phobos.
Jan 31 2013
On Friday, 1 February 2013 at 01:07:32 UTC, H. S. Teoh wrote:On Fri, Feb 01, 2013 at 01:47:35AM +0100, Andrej Mitrovic wrote:I found this approach wrong, FormatException already contains useful information that you overwrite. The correct approach from my point of view is "throw new WhateverExceptionEvenFormatException("something wrong in fmt", file, line, exc)"; If Throwable was designed with encapsulation in mind, the code above was not be possible. Overwriting exc with new information will tell that the problem is in "fmt" not in "format".On 2/1/13, Sean Kelly <sean invisibleduck.org> wrote:+1. Like this idea, I'll have to start using it to avoid the headache of trying to figure out where something blew up when the stacktrace points to some deep obscure code inside Phobos. TI think the reason is mostly historic--the original exception classes had public members. There's no reason why they couldn't be hidden behind read-only properties though, other than the potential to break existing code.I'd rather we not, it's useful being able to modify msg and line sometimes, e.g.: http://forum.dlang.org/thread/uudharkmihxjymsxcyxq forum.dlang.org#post-mailman.855.1359491827.22503.digitalmars-d-learn:40puremagic.com Another example, wrapping `format` to inject the local file and line: string fmt(string file = __FILE__, size_t line = __LINE__, Args...)(string fmtStr, Args args) { try { return format(fmtStr, args); } catch (FormatException exc) { exc.file = file; exc.line = line; throw exc; } } Saves me from having to read a broken stack trace or file and line within Phobos.
Jan 31 2013
On 2/1/13, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:+1. Like this idea, I'll have to start using it to avoid the headache of trying to figure out where something blew up when the stacktrace points to some deep obscure code inside Phobos.Self pro-tip: Wrap it in a template so you can do: alias ExcWrap!(myFunc, Exception1, Exception2) myFunc; This would wrap myFunc and inject file+line of the call site if Exception1 or Exception2 is caught.
Jan 31 2013
On 2/1/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:Self pro-tip: Wrap it in a templateHere, and I didn't even have to use string mixins: import std.format; template Wrap(alias func, Exceptions...) { auto ref Wrap(string file = __FILE__, size_t line = __LINE__, Args...)(Args args) { foreach (Ex; Exceptions) { try { return func(args); } catch (Ex exc) { exc.file = file; exc.line = line; throw exc; } } assert(0); // silence compiler } } void foo(int x) { if (x) throw new Exception(""); else throw new FormatException(""); } void main() { foo(0); // L37: std.format.FormatException test.d(32): foo(1); // L38: object.Exception test.d(30): alias Wrap!(foo, FormatException, Exception) myFoo; myFoo(0); // L41: std.format.FormatException test.d(41): myFoo(1); // L42: object.Exception test.d(42): }
Jan 31 2013
On Friday, February 01, 2013 01:47:35 Andrej Mitrovic wrote:Another example, wrapping `format` to inject the local file and line: string fmt(string file = __FILE__, size_t line = __LINE__, Args...)(string fmtStr, Args args)Just remember that that means that you'll get a new template instantiation every time you use it (unless you did multiple on the same line). - Jonathan M Davis
Jan 31 2013