On Mon, Feb 20, 2012 at 11:11:08AM -0600, Andrei Alexandrescu wrote: > On 2/20/12 11:05 AM, foobar wrote: [...] > >Separation of concerns - exceptions are meant to notify the > >*developer* of errors. User facing error messages is a separate > >concern that exceptions should not be responsible for. it's not just > >outsourcing the translation strings, it's the developer's job to > >determine what if at all should be done with the exception. > > At the end of the day, a human-readable error message must be properly > formatted given some exception that signaled an error. So I disagree > that exceptions are meant for the developer. They are mechanism, a > means to an end.
No, exceptions *are* meant for the developer, because it's the developer who decides whether and how to to display it to the user. > >Trivial example: My mom enters a misspelled URL (e.g. goggle.com) in > >her browser, she does not know or care what 404 means. instead she > >gets a formated page suggesting her to check her spelling and > >probably a suggestion to try google.com instead. > > Sure, and the question is how the message gets created. By encoding *useful* information in the exception, not just some generic stuff lacking in semantic meaning, so that the code that catches the exception knows what the problem is, and can make a sensible decision as to how to display it (or not display it, but react in some other way). Again, this brings us back to class hierarchies. In order to react sensibly to an exception, the code that catches it *has* to know what it is. There's simply no way around this. Just saying "a problem happened" is unhelpful. Code cannot divine the right course of action just by being told that a problem happened. It *needs* to know *what* happened. And the details of what happened depends entirely on the context in which it happened, so the most sensible solution is to use a class hierarchy where you add information to the bottom levels -- that's because that's where the information is!! At the end of the day, using a Variant is no better than using a deep class hierarchy. You're just encoding the exact same structure of information in a different way. You *still* have to know what kind of information is available in the Variant, just like you need to know which exception subclass to catch so that you can access the member variable that tells you what went wrong. For user-facing code, you *need* the catching code to understand what kinds of exceptions can happen so that it can decide whether/how to display it to the user. At my work project, we have a user-facing client-side GUI, and a server-side infrastructure which includes, among other things, a SQL database. There's a middle layer built over the SQL layer that provides various application-specific functions. Both layers can encounter any number of errors. But you know what? The GUI side code displays almost all of these errors as "internal error" to the user. Why? Because the user doesn't know, nor care, that SQL error 1234 occurred. They don't care that middle layer exception 2345 occurred. None of this makes any sense to them. The *developers* care which error it is, so these errors are logged to a *debug channel* that only the developers care to read. It's not even in the regular syslog, because the user admins who read the syslog wouldn't understand what the heck the messages mean anyway. All that's logged is "internal error". Only a few relevant errors from the lower layers are actually translated by the GUI code. User-relevant errors such as "name already exists", "serial number mismatch", and things like that. Which are only a small subset of problems that could potentially occur. In this light, it doesn't make sense to have a fully generic, full-fledged i18n system encoded into Exception (i.e., into every single error the system might encounter). Only a tiny subset of exceptions even *need* to see the light of day, and require i18n. The developers don't care about i18n -- in fact, it's harmful, because it obscures exactly what the error was. If the code throws "Bad parameter error", the developers want to see the exact string "Bad parameter error". The last thing they want is to read this string in Japanese, and then have to figure out what on earth it corresponds with in the code. Translation is only needed for that small subset of errors that is actually meaningful to the end-user. Errors meant for the developers need not, and should not, be translated at all. So then, how does the GUI code know what to translate and what not to translate? That's where an exception class hierarchy is necessary. A hierarchy that allows the code to specifically catch FileNotFoundException and translate that, and leave out other stuff like OracleError1234, ConfigFileParseError, and all the stuff that users don't even remotely understand. Phobos should *not* be the one making this kind of decision. What it needs to do is full information disclosure, and let the catch code make use of it as it sees fit. > >the exception notifies the developer of the error, the developer does > >extra processing (e.g. to suggest similar valid websites) and the > >user get a friendly notification. clearly it doesn't make sense to > >put all this into the exception. > > That extra processing must format the message given the information > passed by the exception. _Definitely_ it doesn't make sense to put the > formatting processing in the exception. That's why shipping the > information outside the exception in a generic format is necessary, > hence the Variant[string]. [...] You're just reinventing class hierarchies using variants. To what end? T -- IBM = I Blame Microsoft