
I have a small idea. I'm curios if anybody else thinks it's a good idea... How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable? For example, you look up a key in a Map. You know the key is there, because you just put it there yourself two seconds ago. But, theoretically, lookup returns a Maybe x so - theoretically - it's possible it might return Nothing. No matter what you do, GHC will insert code to check whether we have Just x or Nothing, and in the Nothing case throw an exception. Obviously there is no way in hell this code path can ever be executed. At least, assuming your code isn't broken... This is where the pragma comes in. The idea is that you write something like case lookup k m of Just v -> process v Nothing -> {-# IMPOSSIBLE "lookup in step 3" #-} When compiled without optimisations, the pragma just causes an exception to be thrown, rather like "error" does. When compiled with optimisations, the whole case alternative is removed, and no code is generated for it. (And if the impossible somehow happens... behaviour is undefined.) So you test your program with your code compiled unoptimised, and when you're "sure" the impossible can't happen, you tell the compiler to remove the check for it. (Actually, it would possibly be a good idea to have a switch to turn this on and off seperately if needed...) Does anybody think this is a useful idea? If so I'll add a feature request ticket to the GHC Trac. But I want to see if folks like the idea first... (I was thinking the message in the pragma would be what gets displayed on screen, along with some auto-generated location info. Just a module name and line number ought to be sufficient...)

On Sat, 2008-06-14 at 19:58 +0100, Andrew Coppin wrote:
I have a small idea. I'm curios if anybody else thinks it's a good idea...
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
For example, you look up a key in a Map. You know the key is there, because you just put it there yourself two seconds ago. But, theoretically, lookup returns a Maybe x so - theoretically - it's possible it might return Nothing. No matter what you do, GHC will insert code to check whether we have Just x or Nothing, and in the Nothing case throw an exception.
Obviously there is no way in hell this code path can ever be executed. At least, assuming your code isn't broken... This is where the pragma comes in. The idea is that you write something like
case lookup k m of Just v -> process v Nothing -> {-# IMPOSSIBLE "lookup in step 3" #-}
When compiled without optimisations, the pragma just causes an exception to be thrown, rather like "error" does. When compiled with optimisations, the whole case alternative is removed, and no code is generated for it. (And if the impossible somehow happens... behaviour is undefined.) So you test your program with your code compiled unoptimised, and when you're "sure" the impossible can't happen, you tell the compiler to remove the check for it. (Actually, it would possibly be a good idea to have a switch to turn this on and off seperately if needed...)
Does anybody think this is a useful idea? If so I'll add a feature request ticket to the GHC Trac. But I want to see if folks like the idea first...
I think it's a horrible idea.

On Sat, 14 Jun 2008, Andrew Coppin wrote:
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable? ... When compiled without optimisations, the pragma just causes an exception to be thrown, rather like "error" does. When compiled with optimisations, the whole case alternative is removed, and no code is generated for it. (And if the impossible somehow happens... behaviour is undefined.) So you test your program with your code compiled unoptimised, and when you're "sure" the impossible can't happen, you tell the compiler to remove the check for it. (Actually, it would possibly be a good idea to have a switch to turn this on and off seperately if needed...)
I think it is another instance of mixing up errors and exceptions (you know the haskellwiki pages ...) Since an 'error' marks a programming error (which should never occur) it would not hurt the program if all 'error's are replaced by 'undefined', an illegal memory access or any other misbehaviour. So 'error' is exactly what you propose as IMPOSSIBLE pragma. A compiler option for replacing all 'error's by nops would do want you want.

Henning Thielemann wrote:
I think it is another instance of mixing up errors and exceptions (you know the haskellwiki pages ...)
Since an 'error' marks a programming error (which should never occur) it would not hurt the program if all 'error's are replaced by 'undefined', an illegal memory access or any other misbehaviour. So 'error' is exactly what you propose as IMPOSSIBLE pragma. A compiler option for replacing all 'error's by nops would do want you want.
OK, so suppose I write a module that contains a function that accepts a number parameter, and that parameter must be greater than 2. I have no control over what value users of the library pass to my function. Suppose some client calls my function with 1 as an argument - is that an error, or an exception? On the other hand, suppose I write the same function, but now it's not exported. So the only code that can possibly call this function is my own code. So I can [theoretically] guarantee it will never be called with the "wrong" argument [assuming the code I write isn't defective]. As far as I can tell, there's no way of making this distinction in Haskell code. You'd use "error" in both cases - or if you're feeling brave, remove it in the second case and hope you're right. I'm just saying it would be nice to be able to keep it in the code for maintainability's sake, but not have the runtime penalty for it once you're "sure" your code is safe. It looks like Don's "assert" thing might be able to do this. [I had no idea this existed by the way...] Hmm, this gives me a new idea for a feature request - how about a function that evaluates to the source code line number it was called from? ;-)

On Sun, 15 Jun 2008, Andrew Coppin wrote:
Henning Thielemann wrote:
I think it is another instance of mixing up errors and exceptions (you know the haskellwiki pages ...)
Since an 'error' marks a programming error (which should never occur) it would not hurt the program if all 'error's are replaced by 'undefined', an illegal memory access or any other misbehaviour. So 'error' is exactly what you propose as IMPOSSIBLE pragma. A compiler option for replacing all 'error's by nops would do want you want.
OK, so suppose I write a module that contains a function that accepts a number parameter, and that parameter must be greater than 2. I have no control over what value users of the library pass to my function. Suppose some client calls my function with 1 as an argument - is that an error, or an exception?
It's an error, like 'head []' is an error. You must document the condition (argument > 2), unfortunately Haskell's type system does not allow to state such conditiions conveniently, and then it's the caller's responsibility to ensure that the argument is greater than 2. I like to distinguish between two kinds of users. (Are there common names for them?) The (consumer) user communicates with your program via an interface you provide: A GUI, the command line, a network. The user may even not know, that the program is written in Haskell. Everything this user makes wrong is an exception. You cannot forbid the user to make something wrong. The other kind of users are programmers, who call functions of your library. This interface is especially fast but in order to get the efficiency you can expect some cooperation by the programmer. E.g. the programmer of your library must ensure that the argument is always greater than 2. Otherwise _he_ has done an _error_. However if he writes a program which lets the user enter the number in a GUI dialog which is then passed to your library, then he must check the number before forwarding it, because the user can do wrong things. If the user enters '1' this is an _exception_. If the programmer does not reject this input it is an error.
On the other hand, suppose I write the same function, but now it's not exported. So the only code that can possibly call this function is my own code. So I can [theoretically] guarantee it will never be called with the "wrong" argument [assuming the code I write isn't defective].
As far as I can tell, there's no way of making this distinction in Haskell code. You'd use "error" in both cases - or if you're feeling brave, remove it in the second case and hope you're right. I'm just saying it would be nice to be able to keep it in the code for maintainability's sake, but not have the runtime penalty for it once you're "sure" your code is safe.
In theory you could remove 'error' in both cases, because in theory neither you nor the library user makes mistakes. In practice you better leave the error, because both of you actually make mistakes.
It looks like Don's "assert" thing might be able to do this. [I had no idea this existed by the way...]
As far as I understand, 'assert' is a wrapper to 'error' which also determines the source code location without using the C preprocessor. Is this correct?
Hmm, this gives me a new idea for a feature request - how about a function that evaluates to the source code line number it was called from? ;-)
Would be also nice for a "single stepper", which shows at which places in the source code things are currently evaluated.

Hmm, this gives me a new idea for a feature request - how about a function that evaluates to the source code line number it was called from? ;-)
Well, that wouldn't be a function, but one of the other "-hc"s (j? n?) has srcloc_annotate which is a macro that does that. It would be nice if ghc had it. Meanwhile, I use -pgmF to replace certain functions with *_srcloc ones that pass a SrcLoc argument, and it works mostly ok. I don't know what other people do, but having file:line in logs and test failures is pretty handy. Only "mostly" because it replaces things in strings, because I can't use cpp because it doesn't understand dots in identifiers, and can't use Language.Haskell.Parser because it *also* doesn't understand dots in identifiers, so it's Regex.subRegex (speaking of not being designed for qualified import...) until I get around to doing it with parsec.

I think when Andy made HPC he added a way to mark code unreachable so it wouldn't "harm" your test coverage report. On Sat, 2008-06-14 at 19:58 +0100, Andrew Coppin wrote:
I have a small idea. I'm curios if anybody else thinks it's a good idea...
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
For example, you look up a key in a Map. You know the key is there, because you just put it there yourself two seconds ago. But, theoretically, lookup returns a Maybe x so - theoretically - it's possible it might return Nothing. No matter what you do, GHC will insert code to check whether we have Just x or Nothing, and in the Nothing case throw an exception.
Obviously there is no way in hell this code path can ever be executed. At least, assuming your code isn't broken... This is where the pragma comes in. The idea is that you write something like
case lookup k m of Just v -> process v Nothing -> {-# IMPOSSIBLE "lookup in step 3" #-}
When compiled without optimisations, the pragma just causes an exception to be thrown, rather like "error" does. When compiled with optimisations, the whole case alternative is removed, and no code is generated for it. (And if the impossible somehow happens... behaviour is undefined.) So you test your program with your code compiled unoptimised, and when you're "sure" the impossible can't happen, you tell the compiler to remove the check for it. (Actually, it would possibly be a good idea to have a switch to turn this on and off seperately if needed...)
Does anybody think this is a useful idea? If so I'll add a feature request ticket to the GHC Trac. But I want to see if folks like the idea first...
(I was thinking the message in the pragma would be what gets displayed on screen, along with some auto-generated location info. Just a module name and line number ought to be sufficient...)
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

andrewcoppin:
I have a small idea. I'm curios if anybody else thinks it's a good idea...
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
For example, you look up a key in a Map. You know the key is there, because you just put it there yourself two seconds ago. But, theoretically, lookup returns a Maybe x so - theoretically - it's possible it might return Nothing. No matter what you do, GHC will insert code to check whether we have Just x or Nothing, and in the Nothing case throw an exception.
Obviously there is no way in hell this code path can ever be executed. At least, assuming your code isn't broken... This is where the pragma comes in. The idea is that you write something like
case lookup k m of Just v -> process v Nothing -> {-# IMPOSSIBLE "lookup in step 3" #-}
You could try using an 'assert' , which has the property of being compiled out at higher optimisation levels. And you can use 'error' or 'undefined' for undefined behaviour. http://www.haskell.org/ghc/docs/latest/html/users_guide/assertions.html Not very Haskelly though. -- Don

Hi
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
Why not make it a function taking a string and returning a value of any type. Then we can keep our language and not break various parsing/type checking properties and rules on pragmas. We can even define it: impossible = error Now you can use tools like Catch and Reach to ensure it is impossible. I think it would be nice to distinguish between: * error - inserted by the compiler * impossible - the programmer knows this can't occur * abort - deliberate aborting because the user made some mistake. The safe library provides abort already. Thanks Neil

On Sat, 14 Jun 2008, Neil Mitchell wrote:
Hi
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
Why not make it a function taking a string and returning a value of any type. Then we can keep our language and not break various parsing/type checking properties and rules on pragmas. We can even define it:
impossible = error
Now you can use tools like Catch and Reach to ensure it is impossible.
I think it would be nice to distinguish between:
* error - inserted by the compiler
Example?
* impossible - the programmer knows this can't occur
This is an error. However the programmer adds a message because he might be wrong.
* abort - deliberate aborting because the user made some mistake.
This is an exception. The signature of a function must reflect this by a Maybe, Either type etc. http://www.haskell.org/haskellwiki/Exception http://www.haskell.org/haskellwiki/Error

Hi
* error - inserted by the compiler
Example?
Pattern-match errors.
* abort - deliberate aborting because the user made some mistake.
This is an exception. The signature of a function must reflect this by a Maybe, Either type etc.
Disagree. I mean more like: when (Delete `elem` flags && Keep `elem` flags) $ abort "User cannot pick both keep and delete on the command line" Think "die" in Perl world. Thanks Neil

On Sat, 14 Jun 2008, Neil Mitchell wrote:
Hi
* error - inserted by the compiler
Example?
Pattern-match errors.
Calling a function with patterns it cannot process is a programming error.
* abort - deliberate aborting because the user made some mistake.
This is an exception. The signature of a function must reflect this by a Maybe, Either type etc.
Disagree. I mean more like:
when (Delete `elem` flags && Keep `elem` flags) $ abort "User cannot pick both keep and delete on the command line"
Think "die" in Perl world.
I wouldn't use such a function, because it does not scale. E.g. I cannot code a loop which lets the user enter flags until they match the conditions. Thus instead of 'abort' I would throw an exception - which is equivalent to the use of an exceptional value like Nothing or Left in Haskell (maybe wrapped in ErrorT).

Neil Mitchell wrote:
* abort - deliberate aborting because the user made some mistake. This is an exception. The signature of a function must reflect this by a Maybe, Either type etc.
Disagree. I mean more like:
when (Delete `elem` flags && Keep `elem` flags) $ abort "User cannot pick both keep and delete on the command line"
Think "die" in Perl world.
in that case should use abort :: String -> IO a, not abort :: String -> a. "abort" as "pure function" is just for messy scripting convenience a-la Perl. (Which is not to say that's never useful, of course -- I would just try my hardest to avoid it in my code, probably.) On the other hand, Control.Exception.throw, if it's ever useful, obviously isn't meant to indicate a programmer error, but to throw an exception (that will probably be caught somewhere in the program's IO). So there's a reason for _|_ besides programmer error (well, there's also user-driven nontermination such as when an interpreter is told to execute an infinite loop :-) -Isaac

Does anybody think this is a useful idea? If so I'll add a feature request ticket to the GHC Trac. But I want to see if folks like the idea first...
Mmmh.. dont' know. Even Java folks don't allow this kind of creeping bug and I guess they know why. You never want undefined behaviour at least when using haskell. Because if that error occurs it's hard to debug, no I don't like that at all. May I look at your proposal from another view? Am I right that you ask for not having to run the "fromJust" code to save some cpu cycles? Very simple example : let list = [ (a,a*a) | a <- [1..10] ] in .. Now getting the square of 4 (standard) fromJust $ lookup 4 list Removing the fromJust code thingy leads to: lookupGoodFaith key ((x,v):xs) | key == x = v | otherwise = lookupGoodFaith xs lookupGoodFaith _ (_,v) = v Where is the difference? I don't even compare the key of the last list item, because it must match. So you safe some additional cpu cycles.. The same can be implemented for Data.Map etc.. Marc Weber

Andrew Coppin wrote: <-- cut -->
When compiled without optimisations, the pragma just causes an exception to be thrown, rather like "error" does. When compiled with optimisations, the whole case alternative is removed, and no code is generated for it. (And if the impossible somehow happens... behaviour is undefined.)
So if the compiler optimizes otherwise well you save how much? Something like: * one load from cache (since the next is the pointer which will be needed anyway later and moreover it was created just few insturctions before); almost always should be in L1; so lets say 2 or 3 ticks; moreover this applies only when you do not tag pointers (which can be done for Maybe) * run test instruction on it; 1 tick * conditional jump; should be doable so that it is predicted correctly by default - so you get 1 tick here probably too So you want to save somewhere about 2 to 5 ticks (which with a bit of luck can be shared with other instructions) but you get unsafe execution. Does not sound right to me. There should be other optimizations which can be done and which save more. If it is ever done I hope it will be possible to switch it off. Or the compiler must prove that what I think is impossible is really impossible and then it can do it :-D Peter.

Andrew Coppin wrote:
Obviously there is no way in hell this code path can ever be executed.
Ah, the number of times I've thought that and been wrong :) From a simplistic perspective what I think you're asking for is to have obscure occasions when your program goes wrong with random consequences and doesn't give you an error message. This a programmer's worst nightmare. I can think of several dimensions of bug difficulty When the bug exhibits: Hard : Infrequent at run-time. Medium : Frequent at run-time. Easy : Compile-time. Reproducible: Hard : No obvious pattern or way to induce the error. Medium : A reasonably strong correlation with some precursor. Easy : Happens every time you do a particular thing. Error message: Hard : No error message. Medium : Non-specific error message. Easy : Error message that relates to an identifiable point in your program with relevant state information. Error message location: Medium : Appears on the screen. Easy : Shown on screen and recorded in a log file. Where it happens: Hard : Only on your user's machine or with their configuration. Easy : On all machines. By classifying error messages, for bugs which you have stated are infrequent and difficult to reproduce, as not needing to be displayed or logged you have pushed all these bugs into the seriously hard category. By adding 'undefined' subsequent behaviour you have made these bugs even more difficult. What we should be doing is pushing every bug in the opposite direction - towards the easy end of all the above dimensions. Richard.

Andrew Coppin
I have a small idea. I'm curios if anybody else thinks it's a good idea...
How about a {-# IMPOSSIBLE #-} pragma that documents the fact that a particular point in the program *should* be unreachable?
I might support this in some way or the other _after_ we've got errors that report source file and line number. Before that I will stay, steadfast and stubborn, utterly ignorant of anything with less importance. Just use assert s v = if debug then error s else v in the mean time. -DHAVE_CONFIG_H ;) -- (c) this sig last receiving data processing entity. Inspect headers for past copyright information. All rights reserved. Unauthorised copying, hiring, renting, public performance and/or broadcasting of this signature prohibited.
participants (12)
-
Achim Schneider
-
Andrew Coppin
-
Derek Elkins
-
Don Stewart
-
Evan Laforge
-
Henning Thielemann
-
Isaac Dupree
-
Marc Weber
-
Neil Mitchell
-
Peter Hercek
-
Richard Kelsall
-
Thomas M. DuBuisson