January 30, 2013
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
January 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:
> > 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
January 30, 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:
> > 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
January 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:
>> 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.
January 31, 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.
February 01, 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.
> 
> 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.
February 01, 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.
February 01, 2013
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.
February 01, 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.
February 01, 2013
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):
}