New Hackage category: Error Handling

Hey everyone, When I uploaded my new package, "error-message", I also went ahead and created a new category: "Error Handling". I did this because there are a number of packages related to this issue, so it might be helpful to have them presented together in one place. Thus, if you have or are in the process of writing a package related to this, please consider adding it to this category sometime so that my package doesn't get lonely. :-) Cheers, Greg

Gregory Crosswhite schrieb:
When I uploaded my new package, "error-message", I also went ahead and created a new category: "Error Handling".
"Error handling" is the same as "debugging" for you? I hope it is not intended for generating further confusion about "exception handling" and "debugging" (= help programmers to analyse errors).

Careful Gregory, you've hit a hot-button issue: you have dared to refer to exceptions as errors! For the record, I find this pedanticism misplaced, as the line between the two is rather blurry. Nonetheless, for control-monad-failure and attempt, we purposely refer to the whole slew of "things not succeeding" as "failure"s. Not to be confused with public enemy number 2 of Haskell users: the "fail" function. </tongue-in-cheek> Michael On Fri, Dec 4, 2009 at 5:57 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
Gregory Crosswhite schrieb:
When I uploaded my new package, "error-message", I also went ahead and created a new category: "Error Handling".
"Error handling" is the same as "debugging" for you? I hope it is not intended for generating further confusion about "exception handling" and "debugging" (= help programmers to analyse errors).
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sat, Dec 5, 2009 at 7:41 PM, Ross Paterson
On Sat, Dec 05, 2009 at 05:52:11PM +0200, Michael Snoyman wrote:
For the record, I find this pedanticism misplaced, ...
I think you'll find that's "pedantry".
Hoped someone would comment exactly that ;).
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Sat, 5 Dec 2009, Michael Snoyman wrote:
On Sat, Dec 5, 2009 at 7:41 PM, Ross Paterson
wrote: On Sat, Dec 05, 2009 at 05:52:11PM +0200, Michael Snoyman wrote: > For the record, I find this pedanticism misplaced, ... I think you'll find that's "pedantry".
Hoped someone would comment exactly that ;).
:-) Nonetheless: Although there might be cases, where it is not immediately clear what is "error" and what is "exception" (not to mention, that different people prefer to use the words for the corresponding concepts in a different way, if they would do so consistently, it would be ok), in most cases it is clear. Have you ever tried to handle an "array index out of range" situation at run-time? I think, it cannot be sensibly handled by the program automatically. Thus there is no other way than terminating the program. Thus I'd call this situation an "error" not an "exception". Of course, people like to throw in here a web server as counterexample. So to speak: With respect to exceptions web servers are an exception.

On Sun, Dec 6, 2009 at 12:17 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sat, 5 Dec 2009, Michael Snoyman wrote:
On Sat, Dec 5, 2009 at 7:41 PM, Ross Paterson
wrote: On Sat, Dec 05, 2009 at 05:52:11PM +0200, Michael Snoyman wrote: > For the record, I find this pedanticism misplaced, ...
I think you'll find that's "pedantry".
Hoped someone would comment exactly that ;).
:-)
Nonetheless: Although there might be cases, where it is not immediately clear what is "error" and what is "exception" (not to mention, that different people prefer to use the words for the corresponding concepts in a different way, if they would do so consistently, it would be ok), in most cases it is clear. Have you ever tried to handle an "array index out of range" situation at run-time? I think, it cannot be sensibly handled by the program automatically. Thus there is no other way than terminating the program. Thus I'd call this situation an "error" not an "exception". Of course, people like to throw in here a web server as counterexample. So to speak: With respect to exceptions web servers are an exception.
I think there are plenty of examples like web servers. A text editor with
plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful. Hope my commenting on this subject doesn't become my own form of *pedantry*. Michael

On Sun, 6 Dec 2009, Michael Snoyman wrote:
I think there are plenty of examples like web servers. A text editor with plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.

On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 6 Dec 2009, Michael Snoyman wrote:
I think there are plenty of examples like web servers. A text editor with
plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found. On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what? Michael

On Dec 5, 2009, at 3:00 PM, Michael Snoyman wrote:
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found.
On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what?
As I understand it, an error is a problem which aborts a computation and an exception is a problem that simply needs to be dealt with before the computation can continue. You are correct that there should be as few irrecoverable errors as possible in an application. In particular, if we think of an application as being a whole bunch of sub-computation tied together into a larger computation, then in a sense what we want is for no the failure of no sub-computation to cause the whole application-wide computation to fail. This, however, does not mean that there will be no circumstances under which any sub-computation fails, such as in the case of discovering in the middle of leading a file that it is irrecoverably corrupt. When these circumstances occur, one has an error and not an exception because there is no way to finish loading the file. However, at a higher lever, the sub-computation of loading the file was not necessary for the application to keep running, and so an error in the sub-computation becomes merely an exception when propagated up to the application level. Cheers, Greg

Michael Snoyman wrote:
On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 6 Dec 2009, Michael Snoyman wrote: I think there are plenty of examples like web servers. A text editor with
plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found.
On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what?
The error gets hidden instead of fixed? Cheers Ben

On Mon, Dec 7, 2009 at 5:30 AM, Ben Franksen
Michael Snoyman wrote:
On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 6 Dec 2009, Michael Snoyman wrote: I think there are plenty of examples like web servers. A text editor with
plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found.
On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what?
The error gets hidden instead of fixed?
Cheers Ben
You're right; bad programmers could do this. A good programmer will know to do one of two things when it gets an exception it does not know how to handle:
* Die with an error message. * In cases like web servers, print an informative error message (eg, hopefully more useful than "Prelude: head") and continue doing something else. I think the kind of programmers who just ignore exceptions and try to keep going are what I think of as over-defensive programmers, who in a misguided attempt to make their code more robust think that they should eliminate any possibility of not returning a result. I saw my share of this kind of code at my previous job, and when you're dealing with data processing programs, it's *very* irritating when suddenly you have garbage data because someone thought "huh, this should be negative, will just use the abs function." However, these people will find ways of doing these evils even without exceptions. Bonus: My favorite error-handling line of code at the company was a bit of VBA that went: On Error Goto Hell Michael

Michael Snoyman schrieb:
On Mon, Dec 7, 2009 at 5:30 AM, Ben Franksen
mailto:ben.franksen@online.de> wrote: Michael Snoyman wrote:
> On the other hand, what's so bad about treating errors as exceptions? If > instead of the program crashing on an array-out-of-bound or pattern-match > it throws an exception which can be caught, so what?
The error gets hidden instead of fixed?
Cheers Ben
You're right; bad programmers could do this. A good programmer will know to do one of two things when it gets an exception it does not know how to handle:
It is certainly not the task of a programming language or a library to parent its users. Despite an interesting idea, it will not work, since programmers will simply switch to a different language or library if they feel pushed around. There is an important reason to not simply catch an error and proceed as if it were only an exception: The error might have corrupted some data and there is no general way to recover from that. Say, after detecting an error you might want to close a file that you were working on. But since you are coping with an error, something you did not foresee, you cannot tell whether the file was already closed again or never opened. So it is better to just abort the program. The next higher level, the shell calling your program or the browser calling your plugin, might have registered what have opened and allocated and can reliably free those resources.

On Mon, Dec 7, 2009 at 2:13 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
Michael Snoyman schrieb:
On Mon, Dec 7, 2009 at 5:30 AM, Ben Franksen
mailto:ben.franksen@online.de> wrote: Michael Snoyman wrote:
> On the other hand, what's so bad about treating errors as
exceptions? If
> instead of the program crashing on an array-out-of-bound or
pattern-match
> it throws an exception which can be caught, so what?
The error gets hidden instead of fixed?
Cheers Ben
You're right; bad programmers could do this. A good programmer will know to do one of two things when it gets an exception it does not know how to handle:
It is certainly not the task of a programming language or a library to parent its users. Despite an interesting idea, it will not work, since programmers will simply switch to a different language or library if they feel pushed around.
How did you get from what I said that I have any desire to parent users of a language? I think my sentiment is clear: a bad programmer will do bad things with any tool. I don't care about how a bad programmer might screw things up. In fact, I think your ideas are much more likely to give the feeling of being "pushed around." The only opinion I've stated so far is that it's ridiculous to constantly demand that people follow your definition of error vs exception, since the line is incredibly blurry and it buys you very little. However, my opinion on what libraries should do is simple: Provide a simple, uniform interface for receiving both errors and exceptions, and let the library user decide what to do with them. If they are unhandable, then don't handle them; if a user *does* handle something which can't be dealt with, they fall into the over-defensive bad programmer category and I don't care. Otherwise, it gives people the flexibility that they need in all cases. I think under no circumstances* should a library simply terminate a runtime because it decides to. This is one of the great things of being able to catch all errors. * Of course, there are no absolutes. Ever. Not a single one.
There is an important reason to not simply catch an error and proceed as if it were only an exception: The error might have corrupted some data and there is no general way to recover from that. Say, after detecting an error you might want to close a file that you were working on. But since you are coping with an error, something you did not foresee, you cannot tell whether the file was already closed again or never opened. So it is better to just abort the program.
The next higher level, the shell calling your program or the browser calling your plugin, might have registered what have opened and allocated and can reliably free those resources.
And what if you're calling a library in the same runtime? I think you are
conflating the idea of "treating errors as exceptions", which I think is a good one, and "not letting there be any distinction between errors and exceptions," which is a bad one. The fact that I can use Control.Exception.catch to catch either errors or exceptions, but I can differentiate based on the data type, is IMO a great solution to this issue. I also believe that the failure package is a better** solution to the problem, because it makes it exceedingly clear which error/exception might have occurred. ** Of course, failure cannot handle a lot of what IO exceptions can, so it's a silly comparison in general. However, for the purpose of "good error/exception handling," I think it's a better solution. Michael

On Mon, 7 Dec 2009, Michael Snoyman wrote:
The only opinion I've stated so far is that it's ridiculous to constantly demand that people follow your definition of error vs exception, since the line is incredibly blurry and it buys you very little.
If you have an example that is not contained in my article on the Haskell Wiki, where you think the error vs. exception distinction is not appropriate, please let me know and will think about it. http://www.haskell.org/haskellwiki/Error_vs._Exception

On Mon, Dec 7, 2009 at 9:07 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Mon, 7 Dec 2009, Michael Snoyman wrote:
The only opinion I've stated so far is that it's ridiculous to constantly
demand that people follow your definition of error vs exception, since the line is incredibly blurry and it buys you very little.
If you have an example that is not contained in my article on the Haskell Wiki, where you think the error vs. exception distinction is not appropriate, please let me know and will think about it.
I think it's a silly, unnecessary distinction. Sure, when you're teaching beginning programmers how to deal with out-of-bounds versus file not found, you can use the terminology. But as far as insisting that library authors have their programs die on an error, it's pointless. Having errors thrown as their own type of exception (like AssertionFailed, for example) is a much more resilient option, and for decent programmers who understand they shouldn't just catch every exception and return a default value, there is no downside. I don't care to make systems less resilient to deal with the sub-par programmer. I turn it around: give me an example where it's better for the runtime to exit than for some type of exception to be thrown, and *I'll* think about it ;). Michael

When I was working at Quintus, I came up with a classification which I can simplify something like this: operating system fault Something bad happened (like a remote node going down) that was entirely out of your control. There is nothing you can do to your program to prevent this. Example: power failure. It's still your problem to clean up on your way out. resource faults your program tried to do something possibly meaningful but the system ran out of some kind of resource (cpu limit, memory limit, disc quota, &c) You might respond to this by increasing the limit and trying again. representation faults your program tried to do something meaningful but the system was unable to represent the result (integer overflow, upper case of ÿ in a Latin 1 system, floating point overflow on a non-IEEE system, &c) Your program isn't *wrong* but you will still have to change it. existence errors Your program tried to do something with a (typically external) resource that doesn't exist (missing file) Your program could be wrong but probably isn't. You will have to create the resource or provide a different name. permission errors Your program tried to do something to a (typically external but not always) resource that you do not have permission to do (typically writing to a read-only file) You may have named the wrong resource. If not, you may have to get the permissions for the resource changed, or ask someone else to run the program. domain errors A precondition on the input arguments of an operation was not satisfied (e.g., X/0, sqrt(-1), malformed file name, head []). Your program is definitely wrong. postcondition errors Your program invoked some operation and the precondition for the operation was satisfied, but when it completed, the postcondition was not. The operation you invoked is broken. If it's yours, you will have to fix it. If the precondition was not strong enough, it may be your program at fault. Otherwise, until you can get a fix from someone, you will have to program around it. I didn't find a simple error/exception distinction helpful, and still don't. Take the case of trying to write to "/dev/nul". This is a permission error. If the program is responsible for the name being what it is, it's a mistake in the program. If the user typed the name in, it's the user's mistake. You really can't tell without tracing each value to its origin. I dare

On Tue, 8 Dec 2009, Richard O'Keefe wrote:
When I was working at Quintus, I came up with a classification which I can simplify something like this:
It's certainly possible to classify errors and exceptions in other (also more fine grained) ways ...
operating system fault Something bad happened (like a remote node going down) that was entirely out of your control. There is nothing you can do to your program to prevent this. Example: power failure. It's still your problem to clean up on your way out.
This is an exception. Of course, if the machine your program runs on goes out of power, then neither exception handling nor debugging will help.
resource faults your program tried to do something possibly meaningful but the system ran out of some kind of resource (cpu limit, memory limit, disc quota, &c)
You might respond to this by increasing the limit and trying again.
An exception.
representation faults your program tried to do something meaningful but the system was unable to represent the result (integer overflow, upper case of ÿ in a Latin 1 system, floating point overflow on a non-IEEE system, &c)
Your program isn't *wrong* but you will still have to change it.
It is the responsibility of the programmer to choose number types that are appropriate for the application. If I address pixels on a todays screen I will have to choose at least Word16. On 8-bit computers bytes were enough. Thus, this sounds like an error.
existence errors Your program tried to do something with a (typically external) resource that doesn't exist (missing file)
Your program could be wrong but probably isn't. You will have to create the resource or provide a different name.
Exception
permission errors Your program tried to do something to a (typically external but not always) resource that you do not have permission to do (typically writing to a read-only file)
You may have named the wrong resource. If not, you may have to get the permissions for the resource changed, or ask someone else to run the program.
Exception
domain errors A precondition on the input arguments of an operation was not satisfied (e.g., X/0, sqrt(-1), malformed file name, head []).
Your program is definitely wrong.
X/0, sqrt(-1), head [] are errors Malformed constant file name in your program is an error but it will raise an exception. The fix is to correct the filename, but you will still need the exception handling, since also the file with the correct name might not exist.
postcondition errors Your program invoked some operation and the precondition for the operation was satisfied, but when it completed, the postcondition was not.
The operation you invoked is broken. If it's yours, you will have to fix it. If the precondition was not strong enough, it may be your program at fault. Otherwise, until you can get a fix from someone, you will have to program around it.
This is an error.
Take the case of trying to write to "/dev/nul". This is a permission error. If the program is responsible for the name being what it is, it's a mistake in the program. If the user typed the name in, it's the user's mistake. You really can't tell without tracing each value to its origin.
Sure, the distinction exception/error depends on the source of the data that causes problems.

On Dec 8, 2009, at 12:28 PM, Henning Thielemann wrote:
representation faults your program tried to do something meaningful but the system was unable to represent the result (integer overflow, upper case of ÿ in a Latin 1 system, floating point overflow on a non-IEEE system, &c)
Your program isn't *wrong* but you will still have to change it.
It is the responsibility of the programmer to choose number types that are appropriate for the application. If I address pixels on a todays screen I will have to choose at least Word16. On 8-bit computers bytes were enough. Thus, this sounds like an error.
That kind of attitude might have done very well in the 1960s. In an age when Intel have demonstrated 48 full x86 cores on a single chip, when it's possible to get a single-chip "DSP" with >240 cores that's fast enough to *calculate* MHz radio signals in real time, typical machine-oriented integer sizes run out _really_ fast. For example, a simple counting loop runs out in well under a second using 32-bit integers. The programmer doesn't always have the information necessary to choose machine-oriented integer sizes. Or it might not offer a choice. Or the choice the programmer needs might not be available: if I want to compute sums of products of 64-bit integers, where are the 128-bit integers I need?
domain errors A precondition on the input arguments of an operation was not satisfied (e.g., X/0, sqrt(-1), malformed file name, head []).
Your program is definitely wrong.
X/0, sqrt(-1), head [] are errors
It depends on WHERE THE DATA CAME FROM.
Sure, the distinction exception/error depends on the source of the data that causes problems.
And sadly, the library does not know this, so the library cannot classify problems _that_ way.

On Tue, 8 Dec 2009, Richard O'Keefe wrote:
X/0, sqrt(-1), head [] are errors
It depends on WHERE THE DATA CAME FROM.
If your program actually computes X/0 or sqrt(-1) or head [] your program is buggy, independent from where the zero, the minus one or the empty list comes.
Sure, the distinction exception/error depends on the source of the data that causes problems.
And sadly, the library does not know this, so the library cannot classify problems _that_ way.
To this end the library documentation says: "Precondition: This function must only be called on non-empty lists." If the programmer calls it with an empty list anyway, it's his fault. The library user made the error then. Of course it would be better, if types or contracts could force such restrictions: http://www.haskell.org/pipermail/haskell-cafe/2009-November/068877.html

On Tue, 8 Dec 2009, Richard O'Keefe wrote:
On Dec 8, 2009, at 12:28 PM, Henning Thielemann wrote:
It is the responsibility of the programmer to choose number types that are appropriate for the application. If I address pixels on a todays screen I will have to choose at least Word16. On 8-bit computers bytes were enough. Thus, this sounds like an error.
That kind of attitude might have done very well in the 1960s.
I don't quite understand. If it is not the responsibility of the programmer to choose numbers of the right size, who else? If the operating system uses Int32 for describing files sizes and Int16 for screen coordinates, I'm safe to do so as well. The interface to the operating system could use type synonyms FileSize and ScreenCoordinate that scale with future sizes. But the programmer remains responsible for using ScreenCoordinate actually for coordinates and not for file sizes.
In an age when Intel have demonstrated 48 full x86 cores on a single chip, when it's possible to get a single-chip "DSP" with >240 cores that's fast enough to *calculate* MHz radio signals in real time, typical machine-oriented integer sizes run out _really_ fast. For example, a simple counting loop runs out in well under a second using 32-bit integers.
The programmer doesn't always have the information necessary to choose machine-oriented integer sizes. Or it might not offer a choice. Or the choice the programmer needs might not be available: if I want to compute sums of products of 64-bit integers, where are the 128-bit integers I need?
And the consequence is to ship a program that raises an exception about problems with the size of integers? I'm afraid I don't understand what you are arguing for.

On Dec 8, 2009, at 1:27 PM, Henning Thielemann wrote:
On Tue, 8 Dec 2009, Richard O'Keefe wrote:
On Dec 8, 2009, at 12:28 PM, Henning Thielemann wrote:
It is the responsibility of the programmer to choose number types that are appropriate for the application. If I address pixels on a todays screen I will have to choose at least Word16. On 8-bit computers bytes were enough. Thus, this sounds like an error.
That kind of attitude might have done very well in the 1960s.
I don't quite understand. If it is not the responsibility of the programmer to choose numbers of the right size, who else?
It is the responsibility of the computer to support the numbers that the programmer needs. It is the responsibility of the computer to compute CORRECTLY with the numbers that it claims to support. I repeat: the programmer might not KNOW what the integer sizes are. In Classic C and C89, the size of an 'int' was whatever the compiler chose to give you. In c89, limits.h means that the program can find out at run time what range it got, but that's too late.
If the operating system uses Int32 for describing files sizes and Int16 for screen coordinates, I'm safe to do so as well.
In a very trivial sense, this is true. In any less trivial sense, not hardly. Suppose I am calculating screen coordinates using / x \ / a11 a12 a13 \ / u \ | y | = | a21 a22 a23 | | v | \ 1 / \ 0 0 1 / \ 1 / which is a fairly standard kind of transformation, it is not in general sufficient that u, v, x, and y should all fit into Int16. The intermediate results must _also_ fit. (Assume for the moment that overflow is checked.) If I need to represent *differences* of Int32 pairs, I know perfectly well what type I need: Int33. But there is no such type.
The interface to the operating system could use type synonyms FileSize and ScreenCoordinate that scale with future sizes. But the programmer remains responsible for using ScreenCoordinate actually for coordinates and not for file sizes.
Consider this problem: We are given a whole bunch of files, and want to determine the total space used by all of them. Smalltalk: fileNames detectSum: [:each | (FileStatus fromFile: each) size] The answer is correct, however many file names there are in the collection. But if we're using C, or Pascal, or something like that, we want to do FileCollectionSize fcs = 0; for (i = 0; i < n; i++) { fcs += OS_File_System_Size(filename[i]); } and how on earth do we compute the type FileCollectionSize? Remember, it has to be big enough to hold the sum of the sizes of an *unknown* and quite possibly large number of quite possibly extremely large files, not necessarily confined to a single disc, so the total could well exceed what will fit in FileSize. This is especially so when you realise that there might be many repetitions of the same file names. I can _easily_ set this up to overflow 64 bits on a modern machine. In Haskell, you'd want to switch straight over to Integer and stay there.
In an age when Intel have demonstrated 48 full x86 cores on a single chip, when it's possible to get a single-chip "DSP" with >240 cores that's fast enough to *calculate* MHz radio signals in real time, typical machine-oriented integer sizes run out _really_ fast. For example, a simple counting loop runs out in well under a second using 32-bit integers.
The programmer doesn't always have the information necessary to choose machine-oriented integer sizes. Or it might not offer a choice. Or the choice the programmer needs might not be available: if I want to compute sums of products of 64-bit integers, where are the 128-bit integers I need?
And the consequence is to ship a program that raises an exception about problems with the size of integers?
Yes. Just because the programmer has TRIED to ensure that all the numbers will fit into the computer's arbitrary and application- irrelevant limits doesn't mean s/he succeeded. For that matter, it doesn't mean that the compiler won't use an optimisation that breaks the program. (Yes, I have known this happen, with integer arithmetic, and recently.)
I'm afraid I don't understand what you are arguing for.
I'm arguing for three things. (1) If you look at the CERT web site, you'll discover that there have been enough security breaches due to integer overflow that they recommend working very hard to prevent it, and there's an "As If Ranged" project to enable writing C _as if_ it could be trusted to raise exceptions about problems with the size of integers. It is better to raise an exception than to let organised crime take over your computer. (2) In a language like Ada where the programmer can *say* exactly what range they need, and the bounds can be computed at compile time, and the compiler either does it right or admits right away that it can't, it's the programmer's fault if it's wrong. Otherwise it isn't. (3) Be very worried any time you multiply or divide integers. (INT_MIN / (-1) is an overflow, C is allowed to treat INT_MIN % (-1) as undefined even though it is mathematically 0.) No, make that "be terrified". If you cannot formally verify that results will be in range, use Haskell's Integer type.

I'm wondering, what are we talking about here? - the meaning of "error" and "exception"? - personal responsibility when writing programs? - language features - library functions, runtime implementation etc.? The first two, I think could serve as the basis for an entertaining discussion. Where the third applies, if there are real disagreements it would be helpful to frame the discussion at least partly in those terms, so anyone who has a practical interest in the matter may understand what's being discussed. In my view, the discussion so far has shown that while everyone has interesting and valuable opinions about how various contingencies ought to be handled, in the end it no doubt it must be up to the programmer writing the code ... right? Donn Cave, donn@avvanta.com

On Sat, Dec 5, 2009 at 3:00 PM, Michael Snoyman
On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann
wrote: On Sun, 6 Dec 2009, Michael Snoyman wrote:
I think there are plenty of examples like web servers. A text editor with plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found.
On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what?
Michael
I think the key is in the difference between the user/client and programmer/developer. As Henning has been saying, these roles change as you go through the different levels of the program, but I see the difference between an error and an exception as this: when a problem is relevant to the user/client, it's an exception; when it is irrelevant to the user/client, it's an error. Suppose you were using some sort of exception framework and you got an error from a piece of library code (not the head function) saying that "head" had failed somewhere. This is absolutely meaningless to a client. It just means there's a problem in the library code; it doesn't mean anything is amiss in the client's space. The client basically has to throw the function out, whether by gracefully aborting the program, disabling the plugin, etc. Contrast this with an exception, such as "index not in map." This is entirely relevant to the client. All of the code knows exactly what is going on; it's just that the index isn't in the map. The client can recover from this by, say, substituting a default value, adding the index to the map, etc. Now, suppose the client knew a priori that the index was *supposed* to be in the map. Now this becomes an *error* to the *client* of the client, since there is a bug in the first client's code. I guess my point is that if I have a function, say, sort :: Ord a => [a] -> [a], and sort calls head somewhere in it, there's no point having "sort" throw an exception for "Prelude.head: []" since that means nothing to the client. It would make more sense to have an InternalError type that just says "OK, sorry client, I screwed up, just clean things up as best you can". If really were something that the client could have responded to, sort should have caught the head error inside the function definition and rethrown a different exception; say, SortEmptyListError if your sort function didn't work on empty lists (contrived example, sorry). Alex

On Sun, Dec 6, 2009 at 10:40 PM, Alexander Dunlap
On Sat, Dec 5, 2009 at 3:00 PM, Michael Snoyman
wrote: On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann
wrote: On Sun, 6 Dec 2009, Michael Snoyman wrote:
I think there are plenty of examples like web servers. A text editor with plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I think we can all appreciate why it would be a bad thing is we treat exceptions as errors. For example, I don't want my program to crash on a file not found.
On the other hand, what's so bad about treating errors as exceptions? If instead of the program crashing on an array-out-of-bound or pattern-match it throws an exception which can be caught, so what?
Michael
I think the key is in the difference between the user/client and programmer/developer. As Henning has been saying, these roles change as you go through the different levels of the program, but I see the difference between an error and an exception as this: when a problem is relevant to the user/client, it's an exception; when it is irrelevant to the user/client, it's an error. Suppose you were using some sort of exception framework and you got an error from a piece of library code (not the head function) saying that "head" had failed somewhere. This is absolutely meaningless to a client. It just means there's a problem in the library code; it doesn't mean anything is amiss in the client's space. The client basically has to throw the function out, whether by gracefully aborting the program, disabling the plugin, etc. Contrast this with an exception, such as "index not in map." This is entirely relevant to the client. All of the code knows exactly what is going on; it's just that the index isn't in the map. The client can recover from this by, say, substituting a default value, adding the index to the map, etc. Now, suppose the client knew a priori that the index was *supposed* to be in the map. Now this becomes an *error* to the *client* of the client, since there is a bug in the first client's code.
I guess my point is that if I have a function, say, sort :: Ord a => [a] -> [a], and sort calls head somewhere in it, there's no point having "sort" throw an exception for "Prelude.head: []" since that means nothing to the client. It would make more sense to have an InternalError type that just says "OK, sorry client, I screwed up, just clean things up as best you can". If really were something that the client could have responded to, sort should have caught the head error inside the function definition and rethrown a different exception; say, SortEmptyListError if your sort function didn't work on empty lists (contrived example, sorry).
Alex
(Sorry for replying to myself.) This is, of course, assuming that a non-empty list was not an invariant of the sort function, in which case it would be a programming error on the part of the client that called sort if that happened. Alex

On Mon, Dec 7, 2009 at 8:40 AM, Alexander Dunlap wrote: On Sat, Dec 5, 2009 at 3:00 PM, Michael Snoyman On Sun, Dec 6, 2009 at 12:55 AM, Henning Thielemann
On Sun, 6 Dec 2009, Michael Snoyman wrote: I think there are plenty of examples like web servers. A text editor with plugins? I
don't want to lose three hours worth of work just because some plugin
wasn't written
correctly. For many classes of programs, the distinction between error
and exception is
not only blurred, it's fully irrelevant. Harping on people every time
they use error in
the "wrong" sense seems unhelpful. Hope my commenting on this subject doesn't become my own form of
*pedantry*. In an earlier thread I have explained that one can consider a software
architecture as divided into levels. What is an error in one level (text
editor plugin, web server thread, operating system process) is an
exception
in the next higher level (text editor, web server, shell respectively).
This
doesn't reduce the importance to distinguish between errors and
exceptions
within one level. All approaches so far that I have seen in Haskell just
mix
exceptions and errors in an arbitrary way. I think we can all appreciate why it would be a bad thing is we treat
exceptions as errors. For example, I don't want my program to crash on a
file not found. On the other hand, what's so bad about treating errors as exceptions? If
instead of the program crashing on an array-out-of-bound or pattern-match
it
throws an exception which can be caught, so what? Michael I think the key is in the difference between the user/client and
programmer/developer. As Henning has been saying, these roles change
as you go through the different levels of the program, but I see the
difference between an error and an exception as this: when a problem
is relevant to the user/client, it's an exception; when it is
irrelevant to the user/client, it's an error. Suppose you were using
some sort of exception framework and you got an error from a piece of
library code (not the head function) saying that "head" had failed
somewhere. This is absolutely meaningless to a client. It just means
there's a problem in the library code; it doesn't mean anything is
amiss in the client's space. The client basically has to throw the
function out, whether by gracefully aborting the program, disabling
the plugin, etc. Contrast this with an exception, such as "index not
in map." This is entirely relevant to the client. All of the code
knows exactly what is going on; it's just that the index isn't in the
map. The client can recover from this by, say, substituting a default
value, adding the index to the map, etc. Now, suppose the client knew
a priori that the index was *supposed* to be in the map. Now this
becomes an *error* to the *client* of the client, since there is a bug
in the first client's code. I guess my point is that if I have a function, say, sort :: Ord a =>
[a] -> [a], and sort calls head somewhere in it, there's no point
having "sort" throw an exception for "Prelude.head: []" since that
means nothing to the client. It would make more sense to have an
InternalError type that just says "OK, sorry client, I screwed up,
just clean things up as best you can". If really were something that
the client could have responded to, sort should have caught the head
error inside the function definition and rethrown a different
exception; say, SortEmptyListError if your sort function didn't work
on empty lists (contrived example, sorry). Alex The WrapFailure typeclass in the the failure package makes this kind of
library design fairly straightforward. I think you're making an argument for
treating errors and exceptions the same way.
Michael

On Sat, 5 Dec 2009, Henning Thielemann wrote:
On Sun, 6 Dec 2009, Michael Snoyman wrote:
I think there are plenty of examples like web servers. A text editor with plugins? I don't want to lose three hours worth of work just because some plugin wasn't written correctly. For many classes of programs, the distinction between error and exception is not only blurred, it's fully irrelevant. Harping on people every time they use error in the "wrong" sense seems unhelpful.
Hope my commenting on this subject doesn't become my own form of *pedantry*.
In an earlier thread I have explained that one can consider a software architecture as divided into levels. What is an error in one level (text editor plugin, web server thread, operating system process) is an exception in the next higher level (text editor, web server, shell respectively). This doesn't reduce the importance to distinguish between errors and exceptions within one level. All approaches so far that I have seen in Haskell just mix exceptions and errors in an arbitrary way.
I have just written more details on this topic: http://www.haskell.org/haskellwiki/Error_vs._Exception
participants (8)
-
Alexander Dunlap
-
Ben Franksen
-
Donn Cave
-
Gregory Crosswhite
-
Henning Thielemann
-
Michael Snoyman
-
Richard O'Keefe
-
Ross Paterson