IO monad and lazy evaluation
Glynn Clements
glynn.clements@virgin.net
Wed, 21 May 2003 19:00:06 +0100
Graham Klyne wrote:
> I agree with the surface points you make. It's easy enough to fix the
> problem once you realize it's there. (In my own "real" program, I moved
> the hClose, which meant I had to pass the handle out of the function which
> opened it.)
>
> The underlying thrust of my post was that I thought pure functional
> languages, like Haskell, were supposed to help one avoid such traps by
> ensuring the messy dependencies on ordering didn't arise in the first
> place.
Unfortunately, unless you also have a pure functional operating
system, the ordering of I/O operations matters ;)
As things stand, I don't think I could begin articulate a reliable
> set of rules for avoiding such problems, short of something like "use only
> strict functions in monad-chains". I'm hoping the Haskell community has
> some experience with this kind of issue to offer some more helpful advice,
> or even tools to detect unsafe combinations. Maybe a discussion of safe
> programming patterns would be a useful interim step?
>
> (e.g. Ketil Z. Malde's suggestion of renaming the function to
> hUnsafeGetContents maybe a small step in the right direction?)
Well, it is implemented using unsafeInterleaveIO; I'm not sure why
lazy I/O generally is considered unsafe but the specific cases of
readFile, hGetContents etc aren't.
> Thinking some more... I'm reminded of some discussions I had a few years
> ago about the timing of calls to Java finalizers, and problems this could
> cause for network I/O programs because using finalizers to close network
> sockets would lead to unexpected resource problems. The only reliable
> solution was to always close the sockets explicitly when done. With Java,
> coming from C/C++, it was possible to get into a mindset that automatic
> memory management also meant automatic management of all resources,
> including all those that weren't directly visible to the programmer. Maybe
> there's a similar trap for the unware in Haskell?
More generally, the concept of "visible" semantics depends upon your
(highly subjective) definition of "visible". I'm reminded of a recent
BugTraq post regarding wiping sensitive information from memory; the
code was basically:
char password[...];
read_password(password);
do_something(password);
memset(password, 0, sizeof(password));
return;
The compiler inlined the memset(), then noted that the contents of the
password array weren't used after the overwrite, so it optimised the
overwrite away.
--
Glynn Clements <glynn.clements@virgin.net>