
I am writing a program that reads and writes to the same file. I was having some problems with it writing to the file before it read it. I solved it in the following two ways: 1. main = do text <- readFile "test" let something = somefunc text writeFile "test2" something renameFile "test2" "test" 2. main = do text <- readFile "test" let something = somefunc text writeFile "test" $! something Are both of these correct (guaranteed to give the behavior I want)? Which is better (and why)? Thanks!

kuq32tr02@sneakemail.com wrote:
I am writing a program that reads and writes to the same file. I was having some problems with it writing to the file before it read it. I solved it in the following two ways:
1. main = do text <- readFile "test" let something = somefunc text writeFile "test2" something renameFile "test2" "test"
2. main = do text <- readFile "test" let something = somefunc text writeFile "test" $! something
Are both of these correct (guaranteed to give the behavior I want)? Which is better (and why)?
The two versions have substantially different behaviour. E.g.:
1. If there were any additional hard links to "test", version 1 would
result in those links referring to the original file, which would
continue to exist alongside the new file.
2. If another process was concurrently reading "test", version 1 would
result in the process reading the original data, while version 2 would
result in it reading the modified data.
3. If you didn't have write permission for "test", version 2 would
fail, while version 1 would succeed so long as you had write
permission on the directory.
4. With version 1, the new version of "test" would have its ownership
and permissions determined by the usual mechanism for creating new
files; typically, the owner would be determined by the process' UID,
the group would be determined by either the process' GID or the group
of the containing directory (BSD vs SysV behaviour), and have its
permissions determined by the process' umask. With version 2, the
ownership and permissions would remain unchanged.
Replacing a file and overwriting a file are substantially different
operations. In general, neither is necessarily more "correct" than the
other, although specific contexts may favour one over the other.
--
Glynn Clements

On Sun, Oct 05, 2003 at 04:25:41AM -0000, kuq32tr02@sneakemail.com wrote:
2. main = do text <- readFile "test" let something = somefunc text writeFile "test" $! something
Are both of these correct (guaranteed to give the behavior I want)? Which is better (and why)?
There is no guarantee that $! will force evaluation of the entire 'something', so you can start writing to file before you finished reading from it. Hopefully it will cause an exception (like in GHC), otherwise you could damage your data (like in Hugs). PS. How does it behave in NHC?
Thanks!
Best regards, Tom -- .signature: Too many levels of symbolic links

On Sun, Oct 05, 2003 at 11:37:16AM +0200, Tomasz Zielonka wrote:
On Sun, Oct 05, 2003 at 04:25:41AM -0000, kuq32tr02@sneakemail.com wrote:
2. main = do text <- readFile "test" let something = somefunc text writeFile "test" $! something
Are both of these correct (guaranteed to give the behavior I want)? Which is better (and why)?
depends on your "somefunc" try: -------------------- somefunc = show . f . read where f :: (Show a, Read a, Num a) => [a] -> (a,a) f ls = (sum (take 3 ls), mul (take 3 ls)) mul :: (Num a) => [a] -> a mul = foldr (*) 1 --------------------- if somefunc read all the needed data before returning the result, then the program will either work correctly or give an exception. I think throwing an exception here is wrong. so: --------------- somefunc = (show . f . read) where f :: (Show a, Read a, Num a) => [a] -> (a,a) f ls = seq (ls!!2) (sum (take 3 ls), mul (take 3 ls)) --------------- must be OK.
There is no guarantee that $! will force evaluation of the entire 'something', so you can start writing to file before you finished reading from it. Hopefully it will cause an exception (like in GHC), otherwise you could damage your data (like in Hugs).
If "test" is not a regular file (say, "/dev/modem"), then it is 100% legal program. So throwing any exception here is not correct (I believe it is done by ghc runtime, since there is nothing exceptional in opening a file for writing already opened for reading, at least in Unix). Anyway such a "defence" will not work with concurrently running programs. -- Max
participants (4)
-
Glynn Clements
-
kuq32tr02@sneakemail.com
-
Max Kirillov
-
Tomasz Zielonka