Proposal: Deprecate and remove Prelude.catch and System.IO.Error.{catch,try}

Hi all, Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865 Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem. These exports are annoying for people who want to use the modern exception handling functions in Control.Exception, as you need to explicitly either import the Prelude with catch hidden, or give the module of the function you want to use. They may also be confusing for beginners, who may not expect to have to use anything other than the catch function in the default scope to catch all exceptions. I believe these functions are only there for historical reasons, and are old cruft that we should tidy up, so I propose that in the base package that comes with GHC 7.2 we deprecate these old functions, and in 7.4 we remove them. Suggested deadline: 24 Jan 2011. Thanks Ian

On 27 December 2010 23:36, Ian Lynagh
Hi all,
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
These exports are annoying for people who want to use the modern exception handling functions in Control.Exception, as you need to explicitly either import the Prelude with catch hidden, or give the module of the function you want to use.
They may also be confusing for beginners, who may not expect to have to use anything other than the catch function in the default scope to catch all exceptions.
I believe these functions are only there for historical reasons, and are old cruft that we should tidy up, so I propose that in the base package that comes with GHC 7.2 we deprecate these old functions, and in 7.4 we remove them.
Suggested deadline: 24 Jan 2011.
I like this proposal; having to explicitly hide Prelude.catch keeps tripping me up/annoying me all the time. -- Ivan Lazar Miljenovic Ivan.Miljenovic@gmail.com IvanMiljenovic.wordpress.com

On Mon, Dec 27, 2010 at 10:43 AM, Ivan Lazar Miljenovic
I like this proposal; having to explicitly hide Prelude.catch keeps tripping me up/annoying me all the time.
+1, I love it as well. -- Felipe.

+1, I've been bitten by this in practice - using Prelude.catch is
nearly never what people want to do, and it's such an easy and obvious
mistake.
On Mon, Dec 27, 2010 at 12:45 PM, Felipe Almeida Lessa
On Mon, Dec 27, 2010 at 10:43 AM, Ivan Lazar Miljenovic
wrote: I like this proposal; having to explicitly hide Prelude.catch keeps tripping me up/annoying me all the time.
+1, I love it as well.
-- Felipe.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Mon, Dec 27, 2010 at 1:36 PM, Ian Lynagh
Hi all,
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
These exports are annoying for people who want to use the modern exception handling functions in Control.Exception, as you need to explicitly either import the Prelude with catch hidden, or give the module of the function you want to use.
They may also be confusing for beginners, who may not expect to have to use anything other than the catch function in the default scope to catch all exceptions.
I believe these functions are only there for historical reasons, and are old cruft that we should tidy up, so I propose that in the base package that comes with GHC 7.2 we deprecate these old functions, and in 7.4 we remove them.
Suggested deadline: 24 Jan 2011.
Thanks Ian
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
+1 It would also be nice to deprecate ioError in favour of the more general throwIO. Bas

On Mon, Dec 27, 2010 at 02:29:04PM +0100, Bas van Dijk wrote:
It would also be nice to deprecate ioError in favour of the more general throwIO.
I'll leave that for a separate proposal. Thanks Ian

On Mon, 27 Dec 2010, Ian Lynagh wrote:
Hi all,
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
This would mean, that Control.Exception.catch remains, that catches also the non-exception "undefined". (I don't like to start a new thread about what to name exception and what error and what names are more appropriate, but I think that many people agree, that there is a fundamental difference between 'throw' and 'error'.) Ok, changing Control.Exception.catch should be a different ticket. After all I think that current exception handling in Control.Exception is only a temporary solution until we have a stable system with explicit exception lists encoded in types. Thus removing one broken temporary solution (Prelude.catch) in order to force people to use the other broken temporary solution (Control.Exception.catch) sounds not good for me.

On Mon, Dec 27, 2010 at 02:37:58PM +0100, Henning Thielemann wrote:
After all I think that current exception handling in Control.Exception is only a temporary solution until we have a stable system with explicit exception lists encoded in types. Thus removing one broken temporary solution (Prelude.catch) in order to force people to use the other broken temporary solution (Control.Exception.catch) sounds not good for me.
I think that while this proposal does not make things perfect, it does make them better, and that perfection is some way off. If anyone agrees with Henning that the change should not be made for this reason, please speak up. Thanks Ian

On Mon, 27 Dec 2010, Ian Lynagh wrote:
On Mon, Dec 27, 2010 at 02:37:58PM +0100, Henning Thielemann wrote:
After all I think that current exception handling in Control.Exception is only a temporary solution until we have a stable system with explicit exception lists encoded in types. Thus removing one broken temporary solution (Prelude.catch) in order to force people to use the other broken temporary solution (Control.Exception.catch) sounds not good for me.
I think that while this proposal does not make things perfect, it does make them better, and that perfection is some way off.
For me the currently cleanest solution is to quickly convert an IO action to (ExceptionalT IOError IO a) using Prelude.catch and my explicit-exception package and then define and use my own exceptions additionally to IOError that are explicit in the type. From this perspective extensible-exception with existentially quantified (i.e. hidden) exception type was a step in the wrong direction, that now asks for further steps in the wrong direction. I wonder, how can we safely remove 'catch' from Prelude, at all. I always thought that Prelude is fixed as is. Otherwise Haskell 98 programs will break.

On Mon, Dec 27, 2010 at 02:37:58PM +0100, Henning Thielemann wrote:
On Mon, 27 Dec 2010, Ian Lynagh wrote:
Hi all,
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
This would mean, that Control.Exception.catch remains, that catches also the non-exception "undefined".
Since ``undefined'' should be semantically equivalent to nontermination, and nontermination in general cannot be caught (by the halting problem), Control.Exception.catch has to be considered as impure, while System.IO.Error.catch (also known as Prelude.catch) was intentionally designed to be pure. While System.IO.Error.catch may not be the best tool for all situations, it therefore does have its place. Deprecating the export from the prelude sounds okay (should readFile and writeFile then also be taken out of the Prelude?), but an export of the pure catch from System.IO definitely makes sense. (Since the errors are a documented part of the interface, the way of catching them should be there, too.) Wolfram

On Mon, Dec 27, 2010 at 11:29:29AM -0500, kahl@cas.mcmaster.ca wrote:
Deprecating the export from the prelude sounds okay (should readFile and writeFile then also be taken out of the Prelude?), but an export of the pure catch from System.IO definitely makes sense. (Since the errors are a documented part of the interface, the way of catching them should be there, too.)
But if you want to use both 'catch's in one module, then you're still going to have a name collision. One could say that qualified imports should be used, but having multiple catch's around sounds like a bug waiting to happen (unlike with functions like 'map', which will (almost always) give you a compile time error if you get the wrong one, the wrong 'catch' may silently catch too many or too few exceptions. Perhaps System.IO.Error should export catchIO and tryIO instead? Thanks Ian

On Wed, 29 Dec 2010, Ian Lynagh wrote:
One could say that qualified imports should be used, but having multiple catch's around sounds like a bug waiting to happen (unlike with functions like 'map', which will (almost always) give you a compile time error if you get the wrong one, the wrong 'catch' may silently catch too many or too few exceptions.
Perhaps System.IO.Error should export catchIO and tryIO instead?
If you use a special monad transformer for exception handling (ErrorT, ExceptionalT, EitherT, Attempt ...) then you cannot accidentally use Prelude.catch.

On 12/27/10 08:37, Henning Thielemann wrote:
On Mon, 27 Dec 2010, Ian Lynagh wrote:
Hi all,
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
This would mean, that Control.Exception.catch remains, that catches also the non-exception "undefined".
Today's Control.Exception.catch can easily catch only IOErrors (and in fact its catch-everything mode with SomeException is a nigh-deprecated mode of operation). e `Control.Exception.catch` (\e -> ... e::IOException ...) (IOError is a type synonym for IOException -- you can use either.)

On Mon, Dec 27, 2010 at 12:36:33PM +0000, Ian Lynagh wrote:
Prelude and System.IO.Error both export an old version of catch, which only catches IOError's, and System.IO.Error additionally exports try with the same problem.
These exports are annoying for people who want to use the modern exception handling functions in Control.Exception, as you need to explicitly either import the Prelude with catch hidden, or give the module of the function you want to use.
They may also be confusing for beginners, who may not expect to have to use anything other than the catch function in the default scope to catch all exceptions.
I believe these functions are only there for historical reasons, and are old cruft that we should tidy up, so I propose that in the base package that comes with GHC 7.2 we deprecate these old functions, and in 7.4 we remove them.
The case for removing Prelude.catch is stronger than the one for removing System.IO.Error.{catch,try} -- the new exception interface is not ready for standardization because it relies on existential types and because of concerns over catching asynchronous exceptions.

On Mon, Dec 27, 2010 at 12:36:33PM +0000, Ian Lynagh wrote:
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Suggested deadline: 24 Jan 2011.
Summary so far: Deprecating/removing Prelude.catch seems to have consensus so far, with several people in favour and only one opposed. A couple more people thought that System.IO.Error ought to export functions to handle the exceptions that it talks about. GHC actually can't currently deprecate one export of 'catch' but not the other. Because of this, and because of the possible confusion etc with having 2 'catch' functions, I suggest we add catchIO and tryIO to System.IO.Error too. This will also give the new report a catch function it can refer to without having to worry about existential quantification etc. Thanks Ian

On 01/04/11 13:20, Ian Lynagh wrote:
GHC actually can't currently deprecate one export of 'catch' but not the other. Because of this, and because of the possible confusion etc with having 2 'catch' functions, I suggest we add catchIO and tryIO to System.IO.Error too. This will also give the new report a catch function it can refer to without having to worry about existential quantification etc.
Noooooooooooooooooo! Then "throwIO" will throw an exception and "catchIO" won't catch it. I will feel horribly confused; or at least some people probably will. Thoughts? -Isaac

On 01/05/11 00:07, Isaac Dupree wrote:
On 01/04/11 13:20, Ian Lynagh wrote:
GHC actually can't currently deprecate one export of 'catch' but not the other. Because of this, and because of the possible confusion etc with having 2 'catch' functions, I suggest we add catchIO and tryIO to System.IO.Error too. This will also give the new report a catch function it can refer to without having to worry about existential quantification etc.
Noooooooooooooooooo! Then "throwIO" will throw an exception and "catchIO" won't catch it. I will feel horribly confused; or at least some people probably will. Thoughts?
Perhaps "catchIOError" and "tryIOError"? (I suggest "*IOError" not "*IOException" for consistency with the other functions in System.IO.Error, but "catchIOException" is fine with me too.)

Isaac Dupree schrieb:
On 01/05/11 00:07, Isaac Dupree wrote:
On 01/04/11 13:20, Ian Lynagh wrote:
GHC actually can't currently deprecate one export of 'catch' but not the other. Because of this, and because of the possible confusion etc with having 2 'catch' functions, I suggest we add catchIO and tryIO to System.IO.Error too. This will also give the new report a catch function it can refer to without having to worry about existential quantification etc.
Noooooooooooooooooo! Then "throwIO" will throw an exception and "catchIO" won't catch it. I will feel horribly confused; or at least some people probably will. Thoughts?
Perhaps "catchIOError" and "tryIOError"? (I suggest "*IOError" not "*IOException" for consistency with the other functions in System.IO.Error, but "catchIOException" is fine with me too.)
Dear Haskell programmers ... Mind you that Haskell has a nice module system that allows qualified import. :-) import qualified System.IO.Error as IOErr main = ... IOErr.catch ... is the best we can have. Why changing the name 'catch' to 'catchIOError' in order to support unqualified import?

On Wed, Jan 05, 2011 at 10:22:34PM +0100, Henning Thielemann wrote:
is the best we can have. Why changing the name 'catch' to 'catchIOError' in order to support unqualified import?
http://www.haskell.org/pipermail/libraries/2010-December/015433.html Thanks Ian

On Wed, 5 Jan 2011, Ian Lynagh wrote:
On Wed, Jan 05, 2011 at 10:22:34PM +0100, Henning Thielemann wrote:
is the best we can have. Why changing the name 'catch' to 'catchIOError' in order to support unqualified import?
http://www.haskell.org/pipermail/libraries/2010-December/015433.html
That doesn't sound like arguments against qualified import. There are two approaches: IOError based exception handling and exception handling based on existential quantification. First one is provided in System.IO.Error (exclusively, after Prelude does no longer export 'catch'), second one is provided in Control.Exception. Both solve the same problem (exception handling) in different ways, thus they use the same names. This sounds like a good idea for me! I can just change the import line and can switch between these approaches easily. That's like having 'take' in Data.List, Data.ByteString, Data.ByteString.Lazy etc. That's the entire purpose of modules and qualified import. Now you may object that these approaches can be easily mixed up, throw something using Control.Exception, and try to catch it with System.IO.Error. The problem from my perspective is, that it was wrong to put another exception handling mechanism with hidden exception information into IO. With a monad that is explicit about exceptions, or at least explicit about the possible existence of exceptions other than IOError, it would not be possible to accidentally mix the two approaches. As I said, I think that the extensible-exception mechanism is an interim solution and I would not like to make the old mechanism look worse (by renaming catch to catchIOError and deprecating Prelude.catch) in order to make extensible-exception look better.

(offtopic)
On Tue, Jan 4, 2011 at 7:20 PM, Ian Lynagh
GHC actually can't currently deprecate one export of 'catch' but not the other.
The desire to be able to deprecate an export comes up every now and then. Therefor I just created a feature request for it: http://hackage.haskell.org/trac/ghc/ticket/4879 Regards, Bas

On 04/01/2011 18:20, Ian Lynagh wrote:
On Mon, Dec 27, 2010 at 12:36:33PM +0000, Ian Lynagh wrote:
Deprecate and remove Prelude.catch and System.IO.Error.{catch,try} http://hackage.haskell.org/trac/ghc/ticket/4865
Suggested deadline: 24 Jan 2011.
Summary so far:
Deprecating/removing Prelude.catch seems to have consensus so far, with several people in favour and only one opposed.
A couple more people thought that System.IO.Error ought to export functions to handle the exceptions that it talks about.
GHC actually can't currently deprecate one export of 'catch' but not the other. Because of this, and because of the possible confusion etc with having 2 'catch' functions, I suggest we add catchIO and tryIO to System.IO.Error too. This will also give the new report a catch function it can refer to without having to worry about existential quantification etc.
What about the Haskell 98 compatibility problem? Do we say in GHC 7.2 that the haskell98 package can no longer be used together with base? Cheers, Simon

On 05 Jan, 2011,at 10:38 AM, Simon Marlow

On Wed, Jan 05, 2011 at 10:38:49AM +0000, Simon Marlow wrote:
What about the Haskell 98 compatibility problem? Do we say in GHC 7.2 that the haskell98 package can no longer be used together with base?
I think that's the best choice. The alternative would be being a bit less correct in our H98 support. I just looked at http://bifunctor.homelinux.net/~roel/cgi-bin/hackage-scripts/revdeps/haskell... which claims that haskell98 has 423 reverse deps (of, I think, about 2730 packages). However, I don't expect this number will ever drop unless a change like this forces it to. I just downloaded a random 11 ([1]), and 4 of them actually import no haskell98 modules anyway (including cairo, the one I picked from near the top). Thanks Ian [1] cairo-0.12.0 feed-0.3.7 uulib-0.9.13 XMPP-0.1.2 happstack-helpers-0.52 com-1.2.0 rallod-0.0.1 HaskellNet-0.2.4 fig-1.3.0 hxt-xslt-9.0.0 timeplot-0.2.15
participants (11)
-
Bas van Dijk
-
Felipe Almeida Lessa
-
Henning Thielemann
-
Ian Lynagh
-
Isaac Dupree
-
Ivan Lazar Miljenovic
-
kahl@cas.mcmaster.ca
-
malcolm.wallace
-
Neil Mitchell
-
Ross Paterson
-
Simon Marlow