February 19, 2012
On 2/19/12 9:50 AM, so wrote:
> On Sunday, 19 February 2012 at 00:50:07 UTC, Jonathan M Davis wrote:
>> On Saturday, February 18, 2012 16:46:43 H. S. Teoh wrote:
>>> I can't believe something this simple has to be explained so
>>> elaborately. I thought all of us here knew how to use OO??
>>
>> I think that the problem stems from people frequently using exceptions
>> incorrectly, and many of the C++ programmers probably haven't _ever_
>> seen them used correctly, since I don't think that it's very common
>> for C++ programs to define exception hierarchies - especially not
>> advanced ones like Java has. And when you see a lot of bad exception
>> code, that tends to turn you off to them, and it definitely doesn't
>> show you how to use them correctly.
>>
>> - Jonathan M Davis
>
> Problem is, "no one" using exception handling correctly including
> language experts. There is no consensus on where they are useful or not.
> Neither articles nor codes help you.

Quite so. That's why slapping with the book won't help - there's no book! :o)

Andrei

February 19, 2012
On 2/19/12 9:56 AM, Nick Sabalausky wrote:
> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org>  wrote in message
> news:jhr0vq$24t0$1@digitalmars.com...
>> On 2/19/12 5:22 AM, deadalnix wrote:
>>> Le 19/02/2012 08:05, Andrei Alexandrescu a écrit :
>>>> How about a system in which you can say whether an exception is I/O
>>>> related, network related, recoverable or not, should be displayed to the
>>>> user or not, etc. Such is difficult to represent with inheritance alone.
>>>>
>>>
>>> That may sound great on the paper, but it isn't. The fact that an
>>> exception is recoverable or not depend often on your program and not on
>>> the cause of the exception.
>>
>> This is self-evident. Again, the meaning of "recoverable" is "operation
>> may succeed if retried with the same input". It's a hint for the catch
>> code. Of course the program is free to ignore that aspect, retry a number
>> of times, log, display user feedback, and so on. But as far as definition
>> goes the notion is cut and dried.
>>
>
> WTF? "Recoverable" means "can be recovered from". Period. The term doesn't
> have a damn thing to do with "how", even in the context of exceptions. It
> *never* has. If you meant it as "operation may succeed if retried with the
> same input", then fine, but don't pretend that *your* arbitrary definition
> is "cut and dried".

I think it's a reasonable definition of "can be recovered from" in the context of exceptions.

Andrei

February 19, 2012
On 2012-02-19 15:38, Andrei Alexandrescu wrote:
> On 2/19/12 6:49 AM, Jacob Carlborg wrote:
>> On 2012-02-19 01:09, Andrei Alexandrescu wrote:
>>> On 2/18/12 6:03 PM, Jonathan M Davis wrote:
>>>> On Saturday, February 18, 2012 17:30:10 Andrei Alexandrescu wrote:
>>>>> The alternative is with virtuals. Do you see a lot of virtuals in base
>>>>> exceptions? Do you see dramatically different interface for different
>>>>> exception types?
>>>>
>>>> You mean virtual functions? The problem is that each exception type
>>>> could have
>>>> information specific to _it_ which makes no sense in a base class. For
>>>> instance, Exception does to have errno in it. FileException does.
>>>>
>>>> If we have GetOptException, it should have a variable for which flag
>>>> failed.
>>>> Exception doesn't have that. And what if the flag failed because it
>>>> was given a
>>>> bad argument? Then the exception needs a field for that argument. Then
>>>> you can
>>>> get something like
>>>>
>>>> try
>>>> getopt(args, ...)
>>>> catch(MissingArgumentException mae)
>>>> {
>>>> stderr.writefln("%s is missing an argument", mae.flag);
>>>> return -1;
>>>> }
>>>> catch(InvalidArgumentException iae)
>>>> {
>>>> stderr.writelfln("%s is not a valid argument for %s. You must give it a
>>>> %s.", mae.arg, mae.flag, mae.expectedType);
>>>> return -1;
>>>> }
>>>> catch(UnknownFlagException ufe)
>>>> {
>>>> stderr.writefln("%s is not a known flag.", ufe.ufe);
>>>> return -1;
>>>> }
>>>> catch(GetOptException goe)
>>>> {
>>>> stderr.writefln("There was an error with %s", goe.flag);
>>>> return -1;
>>>> }
>>>> //A delegate that you passed to getopt threw an exception.
>>>> catch(YourException ye)
>>>> {
>>>> //...
>>>> }
>>>> catch(Exception e)
>>>> {
>>>> stderr.writeln("An unexpected error occured.");
>>>> return -1;
>>>> }
>>>>
>>>> You can't do _anything_ like that right now.
>>>
>>> Of course I can. They call it toString(). The code above pretty much
>>> proves my point with so much wonderful irony.
>>>
>>> Andrei
>>>
>>
>> Say you want to do something like what Git does:
>>
>> $ git statu
>> git: 'statu' is not a git command. See 'git --help'.
>>
>> Did you mean this?
>> status
>> $
>>
>> That would be quite hard with just toString.
>
> An exception hierarchy won't make that easier or more modular. What's
> needed there is the command and a table of all commands.
>
> Andrei

The command could be in the exception. Then you would have to look it up against all valid commands. For the command to be in the exception you would need some sort of hierarchy because, as others have said, a command property wouldn't make sense for an exception like FileNotFound, and wouldn't make sense in the base class Exception.

-- 
/Jacob Carlborg
February 19, 2012
I think it depends on the application. For user apps where errors may often simply be reported, type probably doesn't matter. For apps that may want to change their behavior based on certain errors, catching by type can be useful. Also, testing in/out contracts for correctness pretty much relies on exceptions differentiated by type.

As one simple example of where I've found throwing by type useful, I've written back-end apps that interact with a DB. If a DB connection occurs during processing I need to tear down an array of processing functionality and attempt reconnects in a progressive back-off to avoid spinning on reconnect. Throwing just Exception instead of DbException or whatever means a lot of casting or other inspection to find the useful info and re-throwing if I don't care about the exception. If I'm going to do that I pretty much may as well go back to C-style programming and checking return values.

On Feb 18, 2012, at 10:52 AM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> There's a discussion that started in a pull request:
> 
> https://github.com/alexrp/phobos/commit/4b87dcf39efeb4ddafe8fe99a0ef9a529c0dcaca
> 
> Let's come up with a good doctrine for exception defining and handling in Phobos. From experience I humbly submit that catching by type is most of the time useless.
> 
> 
> Andrei
February 19, 2012
On 2012-02-19 17:29, Andrei Alexandrescu wrote:
> On 2/19/12 9:56 AM, Nick Sabalausky wrote:
>> "Andrei Alexandrescu"<SeeWebsiteForEmail@erdani.org> wrote in message
>> news:jhr0vq$24t0$1@digitalmars.com...
>>> On 2/19/12 5:22 AM, deadalnix wrote:
>>>> Le 19/02/2012 08:05, Andrei Alexandrescu a écrit :
>>>>> How about a system in which you can say whether an exception is I/O
>>>>> related, network related, recoverable or not, should be displayed
>>>>> to the
>>>>> user or not, etc. Such is difficult to represent with inheritance
>>>>> alone.
>>>>>
>>>>
>>>> That may sound great on the paper, but it isn't. The fact that an
>>>> exception is recoverable or not depend often on your program and not on
>>>> the cause of the exception.
>>>
>>> This is self-evident. Again, the meaning of "recoverable" is "operation
>>> may succeed if retried with the same input". It's a hint for the catch
>>> code. Of course the program is free to ignore that aspect, retry a
>>> number
>>> of times, log, display user feedback, and so on. But as far as
>>> definition
>>> goes the notion is cut and dried.
>>>
>>
>> WTF? "Recoverable" means "can be recovered from". Period. The term
>> doesn't
>> have a damn thing to do with "how", even in the context of exceptions. It
>> *never* has. If you meant it as "operation may succeed if retried with
>> the
>> same input", then fine, but don't pretend that *your* arbitrary
>> definition
>> is "cut and dried".
>
> I think it's a reasonable definition of "can be recovered from" in the
> context of exceptions.

No it's not. Say you want to save a file. You're saving it in "/" which you don't have permission to write to. The system throws an exception PermissionException, this is a recoverable exception since the application could prompt the user to save the file in a different location.

-- 
/Jacob Carlborg
February 19, 2012
Only a few virtuals--mostly for printing the exception to a log. Any specifics would require catching the exact type.

On Feb 18, 2012, at 3:30 PM, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 2/18/12 5:20 PM, Jonathan M Davis wrote:
>> On Saturday, February 18, 2012 17:13:16 Andrei Alexandrescu wrote:
>>> On 2/18/12 4:26 PM, Jonathan M Davis wrote (abridged):
>>> GetOptException
>>> FlagArgumentMissingException
>>> InvalidFlagArgumentException
>>> UnknownFlagException
>>> FileException
>>> FileNotFoundException
>>> NotFileException
>>> NotDirException
>>> AccessDeniedException
>>> 
>>> I died inside a little.
>> 
>> If you actually want to _handle_ exceptions, how else do you expect to do it? Simply put a code of some kind on the exceptions and then have switch statement to handle them?
> 
> The alternative is with virtuals. Do you see a lot of virtuals in base exceptions? Do you see dramatically different interface for different exception types?
> 
> 
> Andrei
> 
> 
February 19, 2012
On 2/19/12 10:40 AM, Jacob Carlborg wrote:
> The command could be in the exception. Then you would have to look it up
> against all valid commands. For the command to be in the exception you
> would need some sort of hierarchy because, as others have said, a
> command property wouldn't make sense for an exception like FileNotFound,
> and wouldn't make sense in the base class Exception.

Definitely, no argument there! To restate: all I want is to find ways to figure the "right" number of exception types, and the "right" primitives.

Andrei
February 19, 2012
On 2/19/12 10:43 AM, Jacob Carlborg wrote:
> No it's not. Say you want to save a file. You're saving it in "/" which
> you don't have permission to write to. The system throws an exception
> PermissionException, this is a recoverable exception since the
> application could prompt the user to save the file in a different location.

That would be a retry with different state. I agree you could define transiency/recoverability differently, but I think my definition is more useful. This is because it provides a notion of transiency that can be handled regardless of the actual problem.

Andrei


February 19, 2012
Am 19.02.2012 17:27, schrieb Andrei Alexandrescu:
> On 2/19/12 2:21 AM, H. S. Teoh wrote:
>>  Getopt isn't really the best use case for elaborate exception
>>  hierarchies. Perhaps we should use file I/O or network/socket I/O
>>  instead.
>
> This is exactly what we should avoid: regressing to well-trodden ground.
> We shouldn't discuss OOP only in terms of Animal and Mammal, and we
> shouldn't discuss exceptions only in terms of IOException and
> NetworkException. We should look at the "uncomfortable" cases.
>
>
> Andrei

so there is a need to start with collecting the uncomfortable cases - that would ease the complete discussion a lot



February 19, 2012
On Sun, 19 Feb 2012 01:07:44 -0600, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Sunday, February 19, 2012 00:21:38 Robert Jacques wrote:
>> Not to jump on you in particular :) but bad user parameters should never be
>> treated as exceptional. Even bad 'internal' parameters that are passed via
>> the external API aren't exceptional. Programmers being lazy about input
>> parameter checking is how hackers make their money.
>
> I completely disagree. I think that there are many cases where throwing an
> exception on bad parameters is exactly what you should do. Phobos does this in
> many places. Often, the function knows best what it wants, and it's the best
> position to check it. So, having it check the input makes a _lot_ of sense in
> many cases.
>
> For instance, take fromISOExtString on std.datetime.SysTime. Is it at all
> reasonably to expect that the caller is going to verify that the string is
> well-formed according to the ISO standard? No. And it's highly probable tha
> the string being given came from I/O of some kind - be it a file or a socket or
> whatever. So, it makes _way_ more sense for fromISOExtString to check the
> string itself and throw on failure. It's also more efficient to do that, because
> if you checked that the string was valid before passing it to
> fromISOExtString, then you'd be processing the string twice.
>
> There are other cases where you want to use DbC and require that a function is
> given valid arguments. In those cases, you use assertions, so the checks go
> away in release mode. But that's not always the best way to go about. And in
> defensive programming, you end up checking exceptions quite heavily - even in
> release mode - and throwing when they're bad.
>
> The best approach depends on what you're doing, and what the functions are
> used for. But approaches have their place.
>
> - Jonathan M Davis
>

Most of Phobos is an internal library. I think parsing routines are a bad counter-example to my point; combined validation and conversion is generally part of their mandate and we expect them to fail often. We also don't expect the parsing of user input to live deep inside code base; it's almost always done as close to the input as possible (i.e. in the input text box). All too often you end up with code like: try{ parse(...); } catch {...} Also, although less of a problem in D, not ensuring that in input string actually is a string was the source of many a C exploits.