Re: Pattern matching, and bugs

Hello,
Date: Fri, 18 Dec 2009 13:04:47 +0100 From: Andr?s Mocs?ry
switch 1 = "Unchecked"
switch 2 = "Checked"
switch 3 = "Unknown"
switch x = "Nothing"
These general ways really avoid this particular crash, but does something real bad to the code in my opinion.
...snip...
Which leads to the very reason I wrote to you:
I want to propose this for Haskell prime:
I would like to have a way for Haskell, not to crash, when my coders write pattern matching without the above mentioned general case.
I will first make a recommendation, then some comments on your proposal. My recommendation is this: if you know that a function should only be called with certain values, you should create a data type that has *only* those values, like: data ForSwitch = One | Two | Three then your switch function is switch :: ForSwitch -> String and now it can be guaranteed *at compile-time* that switch will never be called with an incorrect argument, because only arguments are available in the ForSwitch type and they're all valid. It's now impossible for another part of the program to generate invalid data. It either generates a ForSwitch, which is guaranteed to be valid, or it doesn't, in which case the code won't typecheck. Note that if you really just want to wrap Int's, you can use a newtype and a smart constructor, which if written correctly gives you the same guarantees but is in my mind less convenient. Now, as for a general response to your proposal, I'm not sure that what you're requesting is possible, and I'm quite certain it would be more trouble than it's worth.
Like having the compiler auto-include those general cases for us, but when those cases got hit, then* instead of crashing*, it *should **report some error* on *stdout *or *stderr*. (It would be even nicer if it cold have been traced.)
What should the program do after reporting an error? Because of Haskell's non-strict evaluation, a function is only evaluated when your program *needs the result*. The compiler can't infer a meaningful value for an arbitrary type, and the only value that can be in every type is undefined. So now the program needs a result of some type (String in your example) and gets an undefined, and then immediately crashes with an "Exception - undefined" error. As for network-corrupted data, the solution is the same. Make a type that reflects *only* the values you want. Then it's the responsibility of the serializer/deserializer to ensure that you have a correct value, using explicit error handling (Maybe or Either come to mind). Then you know that all data in your system is valid, and you only need to worry about invalid data at borders, where the problem is much easier to address. John

On Fri, Dec 18, 2009 at 02:13:02PM +0000, John Lato wrote:
So now the program needs a result of some type (String in your example) and gets an undefined, and then immediately crashes with an "Exception - undefined" error.
I think this is the second time this is said in this thread, but please don't as it may confuse the OP. "undefined"s, including those generated by missing cases, do *not* crash the program. They also do not *immediately* close the program. They are propagated as exceptions are, however most of the time we write programs without explicitly catching them. So the proper wording would be that the "undefined"s propagate through the functions and whenever they reach the top function (i.e. main), they are caught by the runtime system, which prints the String associated with the "undefined" and exits the proccess with an error code. I should note also that *pure* code *can't* catch those "undefined"s. If they could, then Nasty Things Would Happen(TM) and we don't want that. However IO code may catch them without any problem using Control.Exception's functions. HTH and clarifies things, -- Felipe.
participants (2)
-
Felipe Lessa
-
John Lato