www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Throwable class design

reply "rumbu" <rumbu rumbu.ro> writes:
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
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
prev sibling next sibling parent "Mehrdad" <wfunction hotmail.com> writes:
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
prev sibling next sibling parent "rumbu" <rumbu rumbu.ro> writes:
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.


 T

I 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
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 08:32:47 rumbu wrote:
 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.
 
 
 T

I 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.

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 Davis
Jan 30 2013
prev sibling next sibling parent "rumbu" <rumbu rumbu.ro> writes:
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 Davis

Exceptions 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
prev sibling next sibling parent "simendsjo" <simendsjo gmail.com> writes:
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:
 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 Davis

Exceptions 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.

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) }
Jan 30 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 10:05:21 rumbu wrote:
 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 Davis

Exceptions 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.

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 Davis
Jan 30 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 12:43:49AM -0800, Jonathan M Davis wrote:
 On Wednesday, January 30, 2013 08:32:47 rumbu wrote:
 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.
 
 
 T

I 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 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.
 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.


The message is intended for the end-user, not the library code.
 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
prev sibling next sibling parent "rumbu" <rumbu rumbu.ro> writes:
Ok, maybe my thoughts are polluted by some C# programming 
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
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:
 Ok, maybe my thoughts are polluted by some C# programming 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! 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
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 30, 2013 12:40:26 H. S. Teoh wrote:
 On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:
 Ok, maybe my thoughts are polluted by some C# programming 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!

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 Davis
Jan 30 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
 On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:
 Ok, maybe my thoughts are polluted by some C# programming
 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!

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."

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. Kernighan
Jan 30 2013
prev sibling next sibling parent "simendsjo" <simendsjo gmail.com> writes:
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:
 On Wed, Jan 30, 2013 at 09:03:31PM +0100, rumbu wrote:
 Ok, maybe my thoughts are polluted by some C# programming 
 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!

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 Davis

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.
Jan 30 2013
prev sibling next sibling parent "Kagamin" <spam here.lot> writes:
 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
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On Jan 29, 2013, at 10:49 PM, rumbu <rumbu rumbu.ro> wrote:

 I have one question regarding the Throwable, Error and Exception =

=20
 I cannot understand why members like msg, file, line, info or next are =

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
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Feb 01, 2013 at 01:47:35AM +0100, Andrej Mitrovic wrote:
 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.

+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.
Jan 31 2013
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
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
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/1/13, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 Self pro-tip: Wrap it in a template

Here, 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
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
prev sibling parent "rumbu" <rumbu rumbu.ro> writes:
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:
 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.

+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

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".
Jan 31 2013