ANN: H98 FFI Addendum 1.0, Release Candidate 10
Ross Paterson
ross@soi.city.ac.uk
Thu, 5 Jun 2003 10:31:55 +0100
On Thu, Jun 05, 2003 at 09:25:11AM +0200, John Hughes wrote:
> On Wed, 4 Jun 2003, Ross Paterson wrote:
> > + \item[unsafePerformIO ::\ IO a -> a]
> > + Return the value resulting from executing the \code{IO} action.
> > + This value should be independent of the environment;
> > + otherwise, the system behaviour is undefined.
> >
> > Rationale: to preserve equational reasoning, the crucial responsibility
> > of the programmer is to ensure that the action is deterministic. Without
> > that, all bets are off. The next paragraph deals with side effects:
> >
> > If the \code{IO} computation wrapped in \code{unsafePerformIO} performs side
> > effects, then the relative order in which those side effects take place
> > (relative to the main \code{IO} trunk, or other calls to
> > \code{unsafePerformIO}) is indeterminate.
>
> I suggest adding:
>
> Moreover, the side effects may be performed several times or not
> at all, depending on lazy evaluation and whether the compiler
> unfolds an enclosing definition.
>
> This seems to be a common "gotcha" which it would be wise to warn of.
Sure.
> > Having washed our hands of unsafePerformIO applied to non-deterministic
> > actions, we no longer need the third paragraph, which (though scary)
> > provides no useful guidance:
> >
> > - Great care should be exercised in the use of this function. Not only
> > - because of the danger of introducing side effects, but also because
> > - \code{unsafePerformIO} may compromise typing, for example, when it is used
> > - in conjunction with polymorphic references.
>
> Or maybe it would be better to provide some useful guidance? How about,
>
> To preserve the soundness of the type system, the result of
> unsafePerformIO should always have a monomorphic type. For
> example,
>
> listRef = unsafePerformIO (newIORef [])
>
> is unsafe, while
>
> listRef = unsafePerformIO (newIORef ([] :: [Int]))
>
> is type safe. In the first case listRef is assigned type IORef
> [a], which makes it possible to store a list of one type and fetch
> it with a different type.
With the proposed description of unsafePerformIO, neither of these forms
would be meaningful, because they return an environment-dependent value.
I'm suggesting we draw the line there and not say anything about
uses of unsafePerformIO on the other side of it. That is, document
unsafePerformIO enough to serve the FFI, but stipulate limits to preserve
equational reasoning. Other uses of unsafePerformIO (e.g. for global
variables) are useful, but I don't think they belong in the FFI spec.
Maybe unsafePerformIO should have an addendum of its own.