ANN: H98 FFI Addendum 1.0, Release Candidate 10

John Hughes rjmh@cs.chalmers.se
Thu, 5 Jun 2003 09:25:11 +0200 (MET DST)


On Wed, 4 Jun 2003, Ross Paterson wrote:

> - \item[unsafePerformIO ::\ IO a -> a] Execute an \code{IO} action in place of a
> - pure computations.  For the behaviour to be predictable, the IO computation
> - should be free of side effects and independent of its environment.
> ---
> + \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.

>
> 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.

John