February 18, 2012
On Saturday, February 18, 2012 20:20:23 deadalnix wrote:
> I think your oppinion here is shaped by C++. For what I experienced, in C++, exception are only usefull for very important problem you cannot possibly solve, and at the best log the error and exit.
> 
> An exemple is std::bad_alloc .
> 
> However, in D, I think this is more the role of an Errors. Exception are something « softer ». It will alert you on problems your program encounter, but that are recoverable.
> 
> You cannot recover from any exception at any place (sometime, you just
> cannot at all).
> 
> Let's get an exemple : your program ask a file to the user and do some operations with this file. If the file doesn't exists, you can prompt for another file to the user with a meaningful message and start again. However, the first version of your program can just ignore that case and fail with a less specific handler in firsts versions.
> 
> You cannot achieve something like that if you don't have a useful type to rely on. Here something like FileNotFoundException is what you want.
> 
> The type of the exception must depend on the problem you are facing, not on the module that trhow it. I see a lot of people doing the « MyProgramException » or « MyLibException » but that doesn't make sense. In this case, you are just making things harder.
> 
> Back on the original subject, GetOptException is not what you want. As getopt is supposed to handle command line parameters, you'll use exception like : MissingParameterException, WrongFormatException, UnknowParameterException or anything that is meaningful.
> 
> Those Exceptions would inherit from something like CommandLineException. This is useful because it describe what you are facing. Because you cant to know what is the problem, not which piece of code face the problem.
> 
> If this politic is choosen, then It would make sense to have several modules of phobos throwing exceptions of the same type, or inheriting from the same base class.
> 
> Exception type is a convenient way to filter what you catch and what you don't know how to handle at this point.

In general, I agree with all of this. I very much think that having typed exceptions makes a lot of sense. In general, I think that Java got exceptions right (ignoring the issue with checked exceptions). Having typed exceptions works really well.

In the case of getopt, what we want is a GetOptException which is for anything which goes wrong with getopt so that someone can catch that exception type if they want to just handle the case wheree getopt throws but don't want to swallow other exception types by calling exception and pretty much just want to print an error and exit the program or continue without any comand-line arguments if that's what they prefer to do.

Then you have other exception types derived from GetOptException which deal with specific types of issues - such as FlagArgumentMissingException, InvalidFlagArgumentException, UnknownFlagException. Each of those exception types could then give information which specifically pertains to those errors - such as the flag that had a problem, the type that the flag is supposed to receive, the type that the flag actually received, the invalid value that the flag was given, etc. Such exceptions can then allow you to properly handle and report problems with command-line arguments. Right now, all you know is that something went wrong, and pretty much the best that you can do is print out that something went wrong. You can do any decent error handling at all. You need specific exception types which give you the appropriate information in order to do that.

Another example is FileException. It would be benificial to have exceptions like FileNotFoundException, NotFileException, NotDirException, AccessDeniedException, etc which are derived from FileException. Then programs could handle the specific instance of what went wrong nice and cleanly rather than having to look at error codes. At least FileException provides an error code, but that makes for much uglier handling code assuming that you even have any clue what the error codes mean. And since the error codes can vary from OS to OS, you end up with system-specific error handling code if you try and use errno. Whereas if std.file just translated the error code to the correct exception type, you're then very cleanly informed as to what the problem was and can catch the exception based on which situtations you can recover from and which you can't as well as having different catch blocks to handle different problems differently.

Simply having an exception type per module is somewhat better than just having Exception, because it gives you a better idea of what went wrong (e.g. you got a UTFException rather than a FileException), but it's still way too general in a lot of cases, and I can see why some would think that it creates needless boilerplate code. Also, in some cases, having exception types derive from more general exceptions than what the module focuses on can be useful. For instance, Java has IOException as the base for all IOExceptions. FileException could be derived from that, and then std.stream and std.stdio could could have their exception types derive from that as well. Then you could specifically handle all exceptions related to I/O together.

I'm completely sold on typed exceptions, but I think that we could do better with them than we're currently doing.

- Jonathan M Davis
February 18, 2012
On 02/18/2012 10:38 PM, Alex Rønne Petersen wrote:
> On 18-02-2012 22:30, Timon Gehr wrote:
>> On 02/18/2012 10:25 PM, Alex Rønne Petersen wrote:
>>>
>>> I'd just like to add to this that we don't lose anything per se by
>>> introducing specific exception types. People can still catch Exception
>>> if they really, really want.
>>>
>>
>> We gain executable bloat. I don't know how how significant the amount
>> would be.
>
> For a single class

You want to add only one specific exception type?

> that has nothing but a constructor?

They also have vtbls and TypeInfos.

> Negligible IMHO.
>

Possible.
February 18, 2012
On Saturday, February 18, 2012 15:14:04 Andrei Alexandrescu wrote:
> On 2/18/12 1:27 PM, Alex Rønne Petersen wrote:
> > Point taken. I suggested GetOptException initially because, based on usage patterns of std.getopt, it seems to be most common to just catch the exception (be it a parsing error, type coercion error, or whatever) and print it.
> 
> In fact for the vast majority of exceptions it seems to be most common to just catch the exception and print it.
> 
> Tutorial examples never help, either. They go something like:
> 
> try {
>    ... stuff ...
> } catch (DatabaseException e) {
>    print("There was a database exception: ", e);
> } catch (NetworkException e) {
>    print("There was a network exception: ", e);
> }
> 
> etc.

If that's what you're doing, then you can just catch Exception. But if you're actually going to _use_ the fact that you have typed Exceptions, then you can do error handling specific to what went wrong, and it can be very useful.

It becomes even more important with more complex programs. If I call a function, and it throws a FileException, then I know that the operation failed to operate on the file properly and can handle it appropriately, whereas if it threw a ParserException, then I know that it failed in parsing the file and can handle _that_ appropriately. It gets even better when you get more specific exceptions such as FileNotFoundException or FileOpenFailedException, because then you can handle stuff very specific to what exactly what went wrong.

Exception can't give you any of that. All it tells you is that something went wrong, and the best that you can do is print a message like your example does.

I'd hate to see us have a crippled exception hierarchy just because some people mishandle exceptions and simply print out messages on failure in all cases. Obviously sometimes that's what you have to do, but often you can handle them much better, and that's part of the reason that we  have _Exception_ and not just Error. And a proper exception hierarchy can be very benificial to programmers who actually use it correctly.

- Jonathan M Davis
February 18, 2012
On Saturday, February 18, 2012 20:18:53 Nathan M. Swan wrote:
> Here's a compromise I would suggest: we have the different exception types for different exceptional behaviors, but still they all descend from a common exception type that has a field with the module name; this way, the client can choose which way they want to go.

If someone just wants to handle generic exceptions, then they can catch Exception. That's no reason to not actually have a proper exception hierarchy that programmers can use if they want to. Module-specific works on some level precisely because modules generally encompass specific behaviors (e.g. file handling or string handling), but a really well-designed exception hierarchy would not be specifically tied to modules the way that we are now. Rather, we'd have exceptions specific to behaviors, and different modules would reuse exceptions from other modules where appropriate based on what they're doing.

> It would be nice if there was a mixin template that creates an exception class that acts like this; making similar exception classes is annoying.

I've considered creating one (it woud be quite easy), but the problem is that you don't end up with any ddoc documentation for them.

- Jonathan M Davis
February 18, 2012
On 18-02-2012 23:35, Timon Gehr wrote:
> On 02/18/2012 10:38 PM, Alex Rønne Petersen wrote:
>> On 18-02-2012 22:30, Timon Gehr wrote:
>>> On 02/18/2012 10:25 PM, Alex Rønne Petersen wrote:
>>>>
>>>> I'd just like to add to this that we don't lose anything per se by
>>>> introducing specific exception types. People can still catch Exception
>>>> if they really, really want.
>>>>
>>>
>>> We gain executable bloat. I don't know how how significant the amount
>>> would be.
>>
>> For a single class
>
> You want to add only one specific exception type?

No, but I have a hard time imagining that even the accumulated amount of exceptions will matter.

>
>> that has nothing but a constructor?
>
> They also have vtbls and TypeInfos.

True. But aren't we micro-optimizing here?

>
>> Negligible IMHO.
>>
>
> Possible.


-- 
- Alex
February 18, 2012
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.

Andrei

February 18, 2012
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? If you want to go beyond simply printing out an error message when an exception occurs, having a solid exception hierarchy is the way to go. Otherwise, all that your program is has is the knowledge that something went wrong and a message that it could print out to the user which might inform them as to want went wrong, but it has _nothing_ which will help the program itself handle the problem appropriately.

Honestly, I think that on the whole, this is something that Java got right. They might use exceptions for more than they should (e.g. if the odds of a function failing are very high, don't use an exception, have it return whether it succeeded or not - Java pretty much never does that). But on the whole, I think that they have the correct approach.

- Jonathan M Davis
February 18, 2012
Le 18/02/2012 22:14, Andrei Alexandrescu a écrit :
> On 2/18/12 1:27 PM, Alex Rønne Petersen wrote:
>> Point taken. I suggested GetOptException initially because, based on
>> usage patterns of std.getopt, it seems to be most common to just catch
>> the exception (be it a parsing error, type coercion error, or whatever)
>> and print it.
>
> In fact for the vast majority of exceptions it seems to be most common
> to just catch the exception and print it.
>
> Tutorial examples never help, either. They go something like:
>
> try {
> ... stuff ...
> } catch (DatabaseException e) {
> print("There was a database exception: ", e);
> } catch (NetworkException e) {
> print("There was a network exception: ", e);
> }
>
> etc.
>
> Andrei

This is a dumb example. This show more the fact that Java forcing you to catch every single expression is a bad idea than the fact that having several types of exception is bad.

If you have nothing to do with that exception and don't know how to recover from it, just don't catch it. Or catch them all (Pokemon !!!) using catch(Exception e).

You know that « real life » programming is different than a tutorial.
February 18, 2012
On 2/18/12 5:30 PM, deadalnix wrote:
> You know that « real life » programming is different than a tutorial.

Problem is (a) all tutorials suggests you have a world of things to do; (b) all real code does one thing.

Andrei
February 18, 2012
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