The Right Approach to Exceptions

Jonathan M Davis jmdavisProg at gmx.com
Sat Feb 18 14:26:25 PST 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


More information about the Digitalmars-d mailing list