On Sun, 26 Dec 2010 17:12:50 -0800, misno...@gmail.com wrote: > On Dec 23, 3:22 am, Steven D'Aprano <steve > +comp.lang.pyt...@pearwood.info> wrote: >> You seem to have completely missed that there will be no bug report, >> because this isn't a bug. (Or if it is a bug, the bug is elsewhere, >> external to the function that raises the exception.) It is part of the >> promised API. The fact that the exception is generated deep down some >> chain of function calls is irrelevant. > > While the idea of being able to do this (create a general validation > exception) sounds mildly appealing at first, what happens when the > module implementing this documented API and documented error, has a bug? > It seems that the user, or even module developer in the midst of > writing, would now have no tools to easily tackle the problem, and no > useful information to submit in the required bug report.
That's very true, but the same applies to *any* use of encapsulation. Any time you hide information, you hide information (duh!). This doesn't stop us from doing this: def public(x): if condition: return _private(x) elif other_condition: return _more_private(x+1) else: return _yet_another_private(x-1) If you call public(42), and get the wrong answer, it's a bug, but the source of the bug is hidden from the caller. If you have access to the source code, you can work out where the bug lies (which of the three private functions is buggy?) given the argument, but the return result itself does not expose any information about where the bug lies. This is considered an unavoidable but acceptable side-effect of an otherwise desirable state of affairs: information hiding and encapsulation. The caller being unaware of where and how the result is calculated is considered a good thing, and the fact that it occasionally adds to the debugging effort is considered such a trivial cost that it normally isn't remarked upon, except by lunatics and die-hard fans of spaghetti code using GOTO. But I repeat myself. Why should exceptions *necessarily* be different? As I've repeatedly acknowledged, for an unexpected exception (a bug), the developer needs all the help he can get, and the current behaviour is the right way to do it. You won't hear me argue differently. But for a documented, explicit, expected, deliberate exception, Python breaks encapsulation by exposing the internal details of any internal subroutines used to generate that exception. This leads to messy tracebacks that obscure the source of bugs in the caller's code: >>> import re >>> re.compile(r"(") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.6/re.py", line 190, in compile return _compile(pattern, flags) File "/usr/lib/python2.6/re.py", line 245, in _compile raise error, v # invalid expression sre_constants.error: unbalanced parenthesis I think critics of my position have forgotten what it's like to learning the language. One of the most valuable skills to learn is to *ignore parts of the traceback* -- a skill that takes practice and familiarity with the library or function in use. To those who are less familiar with the function, it can be very difficult to determine which parts of the traceback are relevant and which aren't. In this case, the caller has nothing to do with _compile, and the traceback looks like it's an internal bug in a subroutine, when in fact it is actually due to bad input. The experienced developer learns (by trial and error, possibly) to ignore nearly half of the error message in this case. In principle, the traceback could be roughly half as big, which means the caller would find it half as difficult to read and understand: >>> re.compile(r"(") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.6/re.py", line 190, in compile raise error, v # invalid expression sre_constants.error: unbalanced parenthesis With a one-to-one correspondence between the function called, and the function reporting an error, it is easier to recognise that the error lies in the input rather than some internal error in some subroutine you have nothing to do with. Unfortunately there's no straightforward way to consistently get this in Python without giving up the advantages of delegating work to subroutines. It need not be that way. This could, in principle, be left up to the developer of the public function to specify (somehow!) that some specific exceptions are expected, and should be treated as coming from public() rather than from some internal subroutine. I don't have a concrete proposal for such, although I did suggest a work-around. I expected disinterest ("I don't see the point"). I didn't expect the level of hostility to the idea that exceptions should (if and when possible) point to the source of the error rather than some accidental implementation- specific subroutine. Go figure. -- Steven -- http://mail.python.org/mailman/listinfo/python-list