Discussion: Add safeWithFile function

Some care is required to use withFile properly with lazy IO, and people sometimes get it wrong. In some cases, readFile is a suitable replacement. In other cases, however, it may be necessary to ensure the file gets closed in a timely manner, and it may not be necessary to read the whole file. The following seems to do the trick: safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!) Sample use: *SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= putStr module SafeWithFile (safeWithFile) where import Control.DeepSeq import System.IO import Control.Monad safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!)

A priori, I'm -1 on this proposal. It seems too ad hoc, and the motivation does not seem compelling. It also may be confusing, like "when is withFile unsafe?"-confusing. -- Felipe.

Where are you suggesting this library goes? Your `safeWithFile` needs
`NFData`, but that's in `deepseq` which isn't a dependency of `base`.
- ocharles
On Sat, Oct 11, 2014 at 10:10 PM, David Feuer
Some care is required to use withFile properly with lazy IO, and people sometimes get it wrong. In some cases, readFile is a suitable replacement. In other cases, however, it may be necessary to ensure the file gets closed in a timely manner, and it may not be necessary to read the whole file. The following seems to do the trick:
safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!)
Sample use:
*SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= putStr module SafeWithFile (safeWithFile) where import Control.DeepSeq import System.IO import Control.Monad
safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Sun, 12 Oct 2014, Oliver Charles wrote:
Where are you suggesting this library goes? Your `safeWithFile` needs `NFData`, but that's in `deepseq` which isn't a dependency of `base`.
It would certainly be located in 'deepseq' or a dependent library. Maybe Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it is just a deepseq variant of withFile. I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe.

I would support adding this function under the name `withFile`, in a new module exported by the deepseq package, as Henning seems to be suggesting. I don't think it's particularly important, but this pattern arises often enough that I think it's worthwhile. John L. On Mon, Oct 13, 2014 at 12:14 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 12 Oct 2014, Oliver Charles wrote:
Where are you suggesting this library goes? Your `safeWithFile` needs
`NFData`, but that's in `deepseq` which isn't a dependency of `base`.
It would certainly be located in 'deepseq' or a dependent library. Maybe Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it is just a deepseq variant of withFile.
I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I think a lot of people have raised a lot of important concerns. Henning's point, I think, is particularly enlightening: "I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe." It also composes very poorly—using the contents of more than one file to compute a result will lead to a double application of deepseq. I'm not sure how to address those concerns. One possible path is to have a safeHGetContents, along with RULES in Control.DeepSeq to attempt to erase the double deepseq. I would support adding this function under the name `withFile`, in a new module exported by the deepseq package, as Henning seems to be suggesting. I don't think it's particularly important, but this pattern arises often enough that I think it's worthwhile. John L. On Mon, Oct 13, 2014 at 12:14 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 12 Oct 2014, Oliver Charles wrote:
Where are you suggesting this library goes? Your `safeWithFile` needs
`NFData`, but that's in `deepseq` which isn't a dependency of `base`.
It would certainly be located in 'deepseq' or a dependent library. Maybe Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it is just a deepseq variant of withFile.
I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Sun, 12 Oct 2014, David Feuer wrote:
One possible path is to have a safeHGetContents, along with RULES in Control.DeepSeq to attempt to erase the double deepseq.
Is safeHGetContents the same as http://hackage.haskell.org/package/strict-0.3.2/docs/System-IO-Strict.html#v... ?

I was thinking safeHGetContents :: (NFData a) => Handle -> (String -> a) -> IO a and/or safeHGetContents :: (NFData a) => Handle -> (String -> IO a) -> IO a and/or something more explicitly targeting multiple handles (which I think there must be a nice way to do, somehow!). On Mon, Oct 13, 2014 at 3:09 AM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 12 Oct 2014, David Feuer wrote:
One possible path is to have a safeHGetContents, along with RULES in
Control.DeepSeq to attempt to erase the double deepseq.
Is safeHGetContents the same as
http://hackage.haskell.org/package/strict-0.3.2/docs/ System-IO-Strict.html#v:hGetContents
?

On Mon, 13 Oct 2014, David Feuer wrote:
I was thinking
safeHGetContents :: (NFData a) => Handle -> (String -> a) -> IO a
and/or
safeHGetContents :: (NFData a) => Handle -> (String -> IO a) -> IO a
and/or something more explicitly targeting multiple handles (which I think there must be a nice way to do, somehow!).
I see. Then a better name might be DeepSeq.IO.withContents or DeepSeq.IO.withFileContents or DeepSeq.IO.hWithContents I still think, that 'safe' is not a good part of a Haskell function name, because 'safe' should be the default. If at all, we could rename hGetContents to unsafeHGetContents. A nested call to withContents would still run deepseq twice, right?

-1
This feels particularly ad-hoc and sets a strange precedent for "safe"
functions in base.
The overall better solution is to stop mixing lazy IO with withFile. In the
case that someone absolutely must have this, a local definition will be
best for other purple reading the code.
On Oct 11, 2014 2:11 PM, "David Feuer"
Some care is required to use withFile properly with lazy IO, and people sometimes get it wrong. In some cases, readFile is a suitable replacement. In other cases, however, it may be necessary to ensure the file gets closed in a timely manner, and it may not be necessary to read the whole file. The following seems to do the trick:
safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!)
Sample use:
*SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= putStr module SafeWithFile (safeWithFile) where import Control.DeepSeq import System.IO import Control.Monad
safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
participants (6)
-
David Feuer
-
Eric Mertens
-
Felipe Lessa
-
Henning Thielemann
-
John Lato
-
Oliver Charles