Global variables?

Jon Cast jcast@ou.edu
Fri, 31 Jan 2003 13:49:08 -0600


Ralf Hinze <ralf@informatik.uni-bonn.de> wrote:
> > Pavel G. Zhbanov wrote:
> > > Is it even possible to make a "global variable" in Haskell?  If
> > > yes, how?

> > The usual fudge is:

> > 	import IORef
> > 	import IOExts
> >
> > 	globalVar :: IORef Int
> > 	globalVar = unsafePerformIO $ newIORef 0

> > However, beware of creating more than one "global variable" of the
> > same type. If you enable optimisation, common subexpression
> > elimination may result in both names referring to the same IORef.

> John Hughes wrote a nice pearl on the subject, see

> 	http://www.math.chalmers.se/~rjmh/Globals.ps

This paper claims ``unsafePerformIO is unsafe''.  That's not actually
true in the sense meant; unsafePerformIO merely has safety
pre-conditions that the compiler can't check.  However, there's nothing
wrong with using it (or wrapping it) as long as the preconditions are
checked.  In fact, IMO, it's /better/ to use unsafePerformIO in a common
case like this, because exactly when the preconditions are satisfied
will be much better understood.

The precondition (proof obligation) of unsafePerformIO is that the order
in which unsafePerformIOs are performed cannot affect the outcome of the
program.  However, in this case, ordering doesn't matter: the only side
effect is allocation of a new IORef, and IORefs are sufficiently opaque
we don't care (or really know) about un-allocated IORefs while the only
case we care about the now-allocated IORef is when we de-reference it.
But, that forces the IORef, which executes the unsafePerformIO.  So,
whenever we access the variable, it is allocated.  Therefore, the
outcome of the program (regardless of the order of evaluation) is the
same as if all such global variable declarations are executed before
main begins executing.  So, the outcome is independent of the order of
evaluation.

There you go: the precondition of unsafePerformIO is satisfied, so the
usage is safe.

> Cheers, Ralf

Jon Cast