Architecture of Evil: Writing C In Haskell
It’s been a long road, but today our hard work pays off. You can set globals in Haskell! No more fussing about with
State monads, I’m talking big boy non-thread-safe globals. This glorious piece of functionality thanks to the
someGlobal = unsafePerformIO $ newIORef "foo"
This is how you set a global. We create a global called
someGlobal, and give it the initial value of
foo. You’ll notice I wrap that in
unsafePerformIO. Like the name implies, it is perfectly ok* to do this, after all: the
IO Monad exists only to annoy you, and serves no actual purpose.
* Seriously though, don’t ever do this; if I catch you doing this in real code, then we are no longer friends.
This global can be used like so:
main = do g1 <- readIORef someGlobal putStrLn $ show $ g1 writeIORef someGlobal "bar" g2 <- readIORef someGlobal putStrLn $ show $ g2 return ()
Running this code produces the following output:
On A Serious Note
Now that we’ve all had a good laugh; please don’t ever do this. I discovered this module while messing around with the haskell bindings to OpenGL. If you’ve ever used OpenGL for even a second, you surely noticed that there is crazy amounts of state being tracked. Given this, and the fact that nobody is just going to make a “Haskell replacement for OpenGL”, an
IORef seems like a reasonable alternative to some monolithic
State monad transformer stack.
However, aside from supporting legacy C libraries, I can see no good reason to ever use
IORef instead of