Claus Reinke <[EMAIL PROTECTED]> wrote: > > > > import IORef > > > > import IOExts > > > > > > > > globalVar :: IORef Int > > > > globalVar = unsafePerformIO $ newIORef 0
> > > 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. > Which is the main sense in which the 'unsafe' prefix is usually meant > to be interpreted, and that is bad enough (see below, then re-read > John's quote of Simon PJ's description of unsafePerformIO;-). In > particular, the 'unsafe'-prefix is not a hint for the implementation > to treat something with extra care, but a hint for the programmer that > the implementation may shake unsafe expressions around like any other > ones (inlining, cse, ..), even though that is bound to lead to > problems with the hidden side-effects. So you have to be careful. If that weren't what I said, I'd disagree with you :) > It is the programmer's responsibility to verify that none of these > problems matter in the particular case of usage. Since many advances > in compiler technology tend to invalidate those verifications, it is > almost impossible to guarantee safety in such cases Even with sufficiently liberal use of {-# NOINLINE #-}? > - about the best one can hope for is to identify and document > precisely which assumptions need to be made to "guarantee" > safety. Unfortunately, this leaves it to users to figure out whether > the assumptions made by 'unsafe' authors (e.g., no inlining) are still > valid at the point of use.. > Btw, when talking about unsafety in that paper, John also happens to > point out the other little problem with unsafePerformIO: it permits to > break type safety (many a good spirit has stumbled over that > "polymorphic references" problem in other functional languages). > > 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. > There you went.. into one of the many available traps in this > mine-field: > You argue that unallocated IORefs don't matter as long as "the" IORef > is allocated before it is dereferenced. But that's just part of the > problem - what about inlining globalVar, creating multiple IORefs? {-# NOINLINE globalVar #-} :) > Remember that, by using unsafePerformIO, you've given the compiler the > license to treat globalVar as an expression without side-effects, and > for those inlining is a common first step to enable further > optimisations (last time I checked, the language report didn't even > guarantee the sharing on which the globalVar trick depends)! Now there > are multiple side-effects instead of a single one, and read-and > write-accesses are spread out over the multiple copies of your IORef, > none of which is likely to hold the value you'd like it to have.. > Cheers, > Claus Jon Cast _______________________________________________ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe