
Hi all, A bit strange behaviour with hPutStrLn. Consider following program: main = do handle <- openFile "output.txt" WriteMode hPutStrLn handle (unlines contLines2) -- hFlush houtput where contLines2 = flip map [1..2000] $ \x -> show x ++ " been there done that" Outputs file which ends with following lines: 1989 been there done that 1990 been there done that 1991 been there done that 1992 been there done that 199 (END) So the output is truncated. When I uncomment hFlush, file is fully written. Is this expected/documented behaviour? Platform: WinXP, GHC version 6.4.1 -- Regards, Gracjan

On 1/9/06, Gracjan Polak
Hi all,
A bit strange behaviour with hPutStrLn. Consider following program:
main = do handle <- openFile "output.txt" WriteMode hPutStrLn handle (unlines contLines2) -- hFlush houtput where contLines2 = flip map [1..2000] $ \x -> show x ++ " been there done that"
Outputs file which ends with following lines:
1989 been there done that 1990 been there done that 1991 been there done that 1992 been there done that 199 (END)
So the output is truncated. When I uncomment hFlush, file is fully written. Is this expected/documented behaviour?
Platform: WinXP, GHC version 6.4.1
Looks like the buffering is BlockBuffering for your output. Try changing that using hSetBuffering stdout LineBuffering (or NoBuffering). I believe it gets flushed if you close the file as well... /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On 1/9/06, Sebastian Sylvan
On 1/9/06, Gracjan Polak
wrote: Hi all,
A bit strange behaviour with hPutStrLn. Consider following program:
main = do handle <- openFile "output.txt" WriteMode hPutStrLn handle (unlines contLines2) -- hFlush houtput where contLines2 = flip map [1..2000] $ \x -> show x ++ " been there done that"
Outputs file which ends with following lines:
1989 been there done that 1990 been there done that 1991 been there done that 1992 been there done that 199 (END)
So the output is truncated. When I uncomment hFlush, file is fully written. Is this expected/documented behaviour?
Platform: WinXP, GHC version 6.4.1
Looks like the buffering is BlockBuffering for your output. Try changing that using hSetBuffering stdout LineBuffering (or NoBuffering).
Err, you'd want to change the buffering on your handle, not stdout, obviously. :-) -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Mon, Jan 09, 2006 at 04:57:51PM +0100, Gracjan Polak wrote:
Hi all,
A bit strange behaviour with hPutStrLn. Consider following program:
main = do handle <- openFile "output.txt" WriteMode hPutStrLn handle (unlines contLines2) -- hFlush houtput where contLines2 = flip map [1..2000] $ \x -> show x ++ " been there done that"
Outputs file which ends with following lines:
1989 been there done that 1990 been there done that 1991 been there done that 1992 been there done that 199 (END)
So the output is truncated. When I uncomment hFlush, file is fully written. Is this expected/documented behaviour?
This is the usual behavior when file is not closed. And example from http://www.haskell.org/onlinereport/io.html suggests that using hClose is necessary.

On Mon, 9 Jan 2006, Stepan Golosunov wrote:
On Mon, Jan 09, 2006 at 04:57:51PM +0100, Gracjan Polak wrote: ...
So the output is truncated. When I uncomment hFlush, file is fully written. Is this expected/documented behaviour?
This is the usual behavior when file is not closed. And example from http://www.haskell.org/onlinereport/io.html suggests that using hClose is necessary.
I guess it may be the usual behavior for ghc, since it works the same for me on MacOS X. In other languages with similar buffered output, finalizers deal with this automatically on exit, and explicit flush or close is needed only in relatively rare circumstances. C, for example ... in fact, I'm surprised to see this behavior in any I/O library. The point of difference I expect, in more modern languages, is between immediate and deferred finalization. Donn Cave, donn@drizzle.com

Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but am unsure. Since we can't rely on finalizers to run in general, some sort of 'atexit' routine is needed. (which would be a good addition to the standard libraries anyway) John -- John Meacham - ⑆repetae.net⑆john⑈

Thanks for the answers. I can go with hFlush or hClose, no problem here. Anyway this is a bit surprising that default stdout behaves different than file opened with default options. -- Gracjan

John Meacham wrote:
Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but am unsure.
It hasn't been fixed, this is the current behaviour and it's likely to stay that way, I'm afraid. We used to run finalizers on exit, but we stopped doing that for various reasons. Even when we did run finalizers on exit, we couldn't guarantee to run all of them.
Since we can't rely on finalizers to run in general, some sort of 'atexit' routine is needed. (which would be a good addition to the standard libraries anyway)
You can implement atexit quite straightforwardly, if that's what you want. exits = unsafePerformIO (newIORef []) :: IORef [IO ()] main = do_stuff `finally` (readIORef exits >>= sequence_ . reverse) atexit io = modifyIORef exits (io:) In reality you probably want to use weak pointers here. Using this version of atexit to close Handles is bad, because it holds on to the Handle until the end of the program. Better to use a Weak pointer and allow the Handle to be GC'd, but then you still need finalizers. Cheers, Simon

On Tue, Jan 10, 2006 at 09:40:41AM +0000, Simon Marlow wrote:
John Meacham wrote:
Yeah. this is a major bug in ghc IMHO. I believe it has been fixed, but am unsure.
It hasn't been fixed, this is the current behaviour and it's likely to stay that way, I'm afraid.
We used to run finalizers on exit, but we stopped doing that for various reasons. Even when we did run finalizers on exit, we couldn't guarantee to run all of them.
oh, the bug I was refering to was not not running finalizers on exit (which makes sense) but rather not flushing file handles on exit. the implication being that flushing the file handles should be done via some other mechanism than the GC finalizer.
Since we can't rely on finalizers to run in general, some sort of 'atexit' routine is needed. (which would be a good addition to the standard libraries anyway)
You can implement atexit quite straightforwardly, if that's what you want.
exits = unsafePerformIO (newIORef []) :: IORef [IO ()] main = do_stuff `finally` (readIORef exits >>= sequence_ . reverse) atexit io = modifyIORef exits (io:)
The problem is that people would have to know to put that in main, so the atexit functionality could not be used from libraries. I am thinking something more akin to C's atexit(3) function provided by its standard libraries. a proposed interface would be module System.Exit -- append to the current System.Exit data AtExitHandle -- | add a routine to be called on program exit addHandle :: IO () -> IO AtExitHandle -- | remove a routine previously set to be run on program exit, this actios is idempotent. removeHandle :: AtExitHandle -> IO () -- | run and remove a routine atomically, guarenteed to run routine at most once, even if called multiple times runRemoveHandle :: AtExitHandle -> IO () so, hOpen will do an addHandle (hClose h) stowing the AtExitHandle and hClose will do a removeHandle on the AtExitHandle I will happily implement this, I have needed it on several occasions when working on real-world programs especially since the (correct) decision to not ensure finalizers are run. (like making sure the terminal mode is reset, or that certain resources (lock files, SYSV semaphores) are released) in addition, I would add a _exitWith to System.Exit as the obvious parallel to _exit(2). John -- John Meacham - ⑆repetae.net⑆john⑈
participants (6)
-
Donn Cave
-
Gracjan Polak
-
John Meacham
-
Sebastian Sylvan
-
Simon Marlow
-
Stepan Golosunov