4 ms·
As for variance of Exceptions, that's a pipe dream. Imagine a system that has a subsystem that looks something up in a 'database'. ... or it could be using some
by wladimir 15y ago
As for variance of Exceptions, that's a pipe dream. Imagine a system that has a subsystem that looks something up in a 'database'. ... or it could be using something like JDBC (which could throw it's own exceptions).
Some languages try to address this by wrapping exceptions. For example, exception chaining in Python:
http://www.python.org/dev/peps/pep-0344/ http://www.python.org/dev/peps/pep-0344/
The code that uses the subsystem will then be able to catch a meaningful exception (such as CannotCreateDatabaseTable), while for diagnostic purposes it is possible to check out or log the inner exception (such as NetworkTimeout). It's a compromise between "dumbing down" the exception (higher-level information is added, even) and making it impossible to anticipate the possible errors.
- PaulHoule 15y agoJava and C# have inner exceptions built into the base classes and it's not at all hard to implement inner exceptions in other languages like PHP. And you're right, this is a good compromise. When it comes to exceptions (and many other things) you realize some boundaries are more important than others. If you're building, say, a database access library that has a well-defined API, you are better off defining a good set of meaningful exceptions. Inside a particular module, however, creating new exception classes tends to create more problems than it is worth. I can't tell you how many times I've seen basically the same exception defined three or four times by different programmers in different parts of the same system. Even when you look at the "better" examples of exception hierarchies the results are frequently depressingly bad. For instance, many database access APIs just give a SQLException or the equivalent thereof. Some of them will add a huge range of Exceptions that are pretty superfluous such as InvalidTableNameException, InvalidColumnNameException, YouViolatedTheTypingRulesOfDatabaseXException (all of which should be DontProgramaticallyGenerateSQLException) but they never seem to have a DuplicateKeyException which is the one case where you actually might want to do something different from all of the others.
- wladimir 15y agoI haven't programmed Java for a while, so I missed that development. Back when I learned it this didn't exist yet, or at least was rarely used. Yes agreed, database libraries seem to be notably bad in exception reporting. In Python, even though SQL is wrapped in a general layer, exceptions are still different per engine. MySQL has one exception with an error code which makes it very hard to distinguish between even a duplicate key and a network error. Another mistake that many libraries make is that they make a generic 'FooLibraryException' and subclass all their exceptions from there, instead of from where it makes sense (IoError, KeyError, MemoryError ...) But even with those issues, I hugely prefer exceptions to the 'check return value after every call'.
- St-Clock 15y ago"Another mistake that many libraries make is that they make a generic 'FooLibraryException' and subclass all their exceptions from there, instead of from where it makes sense (IoError, KeyError, MemoryError ...)" Actually, this isn't black and white. When I need to create more than one exception class for a library, I prefer to avoid subclassing standard exceptions to prevent that kind of confusing situation: try: afile = open('myfile.txt') content = afile.read() my_library.do_something(content) except IOError: # recover from afile.read() failure If my_library was returning a IOError, you would not know if the problem came from your code or the library code. Moreover, this would leak implementation detail. Of course, you can always get around this by wrapping each library call within a try/catch block, but that does not scale well if you make many calls interspersed with your code.
- wladimir 15y agoWell, at least from a maintainability perspective it's more clear to do try: afile = open('myfile.txt') content = afile.read() except XXX: (handle exception) else: (continue here using content) If you want to capture the exceptions from a certain call. Otherwise, my_library.do_something might start raising a IOError somewhere in its bowels later on, and you have a confusing debug process. When you find that you have a lot of similar or even repeated try/catch blocks, using 'with' context managers might be a good idea. My point was that an IOError is an IOError, wether it's a MongoDBIOError or a MySQLIOError. Yes, you leak some implementation detail (namely, that I/O is used) but do do useful diagnostics you need some (abstract) implementation knowledge... network error: is your router plugged in? io error: is the disk full? keyerror: implementation bug? and so on. Hm maybe this would be a case for multi-inheritance exceptions? MongoDBIOException is both and IOException as a MongoDBException. Don't even know if it's possible, or wise :)