Re: exceptions vs. Either

After all, Java basically does exactly what you're asking for with
Java's head/tail would be doing runtime checks if they are throwing exceptions, static guarantees mean the program would not be allowed to compile if it broke the static guarantees.
end-programmers have to worry much less about handling errors properly.
Which is a bad thing! All programmers always have to consider error conditions, if they don't they write buggy code - that's the nature of the beast. I prefer making programmers expicitly face the decisions they are making, rather than have things implicitly handled in a way that hides what is going on from the programmer. Keean.

After all, Java basically does exactly what you're asking for with
Java's head/tail would be doing runtime checks if they are throwing exceptions, static guarantees mean the program would not be allowed to compile if it broke the static guarantees.
Not so. In Java, the programmer is forced to handle most exceptions by the type system. That is, if the exception is not handled, the program will not compile, thus providing a static guarantee that exceptions are handled. Only "unchecked exceptions" (RuntimeException and Error) are exempt from this check. --KW 8-)

On 06/08/2004, at 7:43 PM, Keith Wansbrough wrote:
Not so. In Java, the programmer is forced to handle most exceptions by the type system. That is, if the exception is not handled, the program will not compile, thus providing a static guarantee that exceptions are handled.
One feature I've always wanted is to be able to tell the compiler or run-time system (whichever is responsible for enforcing the type checks) to turn on exception checking or not. That way, if you are programming in a fast and loose style (e.g. writing a throwaway script), exceptions don't get in your way, and you can program unencumbered by lots of useless error checking code. If you then decide that the throwaway script isn't so throwaway after all, insert a pragma in your program, and get back full static checking. If you know Perl, it's the equivalent of 'use strict;' for exceptions. I hope to see such a design in a Haskell compiler one day ... -- % Andre Pang : trust.in.love.to.save

On 06/08/2004, at 6:56 PM, MR K P SCHUPKE wrote:
After all, Java basically does exactly what you're asking for with
Java's head/tail would be doing runtime checks if they are throwing exceptions, static guarantees mean the program would not be allowed to compile if it broke the static guarantees.
As Keith said, Java will check at compile time whether or not you handle the exception. My point is this: it is impossible to check whether the exception is "properly" handled. If you adjust Haskell's tail function to return (Maybe [a]) instead of just ([a]), you are doing the thing as Java from a pragmatic perspective: you are adding information to the type system that tells the programmer the function may fail. You also suffer the same consequence as Java: you have no idea whether the programmer properly handles the error situation. If I am writing a one-shot, never-use-again script that takes 3 minutes to write, and I _know_ that I'm not going to be feeding the tail function a non-empty list--e.g. because I'm writing a one-shot five-minute script to transform a file from one text format to another, as is the case for lots of Perl programs--then the extra Maybe type just gets in the way. I'll either ignore the Nothing case, or write `case tail foo of ... Nothing -> error "bleh"'. I will go so far to say that such a program can be considered "correct": it does exactly what I want it to do, in exactly the circumstances I desire (0 byte files being specifically excluded from the circumstances!).
Which is a bad thing! All programmers always have to consider error conditions, if they don't they write buggy code - that's the nature of the beast. I prefer making programmers expicitly face the decisions they are making, rather than have things implicitly handled in a way that hides what is going on from the programmer.
It's a question of whether the library designer should impose their will on the library user. As a library designer, do you feel that you are always making the right decision for the library user 100% of the time? I know I never feel like that when I write libraries ... -- % Andre Pang : trust.in.love.to.save

André Pang
As Keith said, Java will check at compile time whether or not you handle the exception.
This sounds very tedious! The right thing to do if you don't handle them, is of course to propagate exceptions up; however, then you need to update a 'throws' clause as you modify your implementation. Sounds like a job for...Type Inference! Wouldn't it be nice if GHCi and Hugs' ":i foo" would tell you about the exceptions it could throw? (No idea how feasible that would be, and I may have misunderstood stuff - it's ages since I wrote Java code) -ketil -- If I haven't seen further, it is by standing in the footprints of giants

This sounds very tedious! The right thing to do if you don't handle them, is of course to propagate exceptions up; however, then you need to update a 'throws' clause as you modify your implementation.
Sounds like a job for...Type Inference! Wouldn't it be nice if GHCi and Hugs' ":i foo" would tell you about the exceptions it could throw?
Do you just want exceptions to be displayed by an interpreter or do you want them used in the compiler (i.e., part of the Haskell language). I think it is straightforward enough to annotate expressions with the exceptions they can raise. As a first attempt, I'll use e :: ty^ex to indicate that an expression e has type ty and can raise exceptions ex. 1/0 :: Int^DivZero [1/i | i <- [0..]] :: [Int^DivZero] head [1/i | i <- [0..]] :: Int^{DivZero,Head_Empty} There's a few problems with simply adding this to Hugs/GHC as they stand though: 1) The exception parts of the types I showed should be types but, at present they are values. 2) Since exceptions accumulate towards the root, it's common to have a way of summarising a set of exceptions. Usually, this is done using some notion of inheritance so that numeric overflow, division by zero, etc might be summarized as 'ArithmeticError'. (Often the inheritance graph is a tree but I suspect it would be useful to have a DAG and to be able to define your own DAG just as you can define your own inheritance using type classes.) 3) This doesn't take the non-deterministic part of Haskell exceptions into account. Implementing the rules in the paper would be a good way of checking that the rules capture all the transformations that compilers like GHC do. Of course, to do this, you really need to push the exception-types all the way through the optimizer since it is the optimizer that introduces non-determinism. -- Alastair Reid

Alastair Reid
Do you just want exceptions to be displayed by an interpreter or do you want them used in the compiler (i.e., part of the Haskell language).
I think it would be difficult, and perhaps undesirable, to make it part of the language. So my immediate thought was that an interactive system could note any calls to functions that could produce exceptions (e.g. performing file operations, division, calls to undefined/error/fail, incomplete patterns...) and tell the user in the response to the :i command.
I think it is straightforward enough to annotate expressions with the exceptions they can raise.
Oleg (reposted by Kean) manages this, but as far as I understand it, it requires additional work by the programmer. As I said, I don't have a lot of experience working with Java, but cluttering the type( annotation)s with exceptions seems to be tedious, especially when you really just want to propagate the exception. E.g. if I rewrite a function so that it no longer uses division, I must potentially change all types up to the level where division-by-zero would be handled. Knowing programmers, I worry that people will write dummy catch clauses that only serve to sweep the exception under the rug.
2) Since exceptions accumulate towards the root, it's common to have a way of summarising a set of exceptions. Usually, this is done using some notion of inheritance so that numeric overflow, division by zero, etc might be summarized as 'ArithmeticError'.
Doesn't this lose information? I can see why it is useful to *catch* larger classes of error, in particular high up when you only deal with it in a generalized way (e.g. reporting the error to the user), but isn't it also useful to know exactly the kinds of error that can occur? -ketil -- If I haven't seen further, it is by standing in the footprints of giants
participants (5)
-
Alastair Reid
-
André Pang
-
Keith Wansbrough
-
Ketil Malde
-
MR K P SCHUPKE