[Haskell] Re: Global Variables and IO initializers

Benjamin Franksen benjamin.franksen at bessy.de
Sun Nov 7 08:45:42 EST 2004

On Sunday 07 November 2004 13:36, you wrote:
> AFAICS the only alternative to..
>  userInit <- oneShot realInit
> is to export realInit, have users create their own userInit, and then pass
> that around as an argument to everything that might make use of userInit.

Yes. For instance, user code executes

	handle <- YourModule.init

and in the rest of the program the handle is used as an argument to those and
only those routines that actually depend on the initialized state represented
by 'handle'. In the Haskell Web Server it turned out that after all it wasn't
that many routines that depended on initialized state.

It's a similar advantage as using the IO monad has over allowing arbitrary
side-effects in functions: The IO monad gives you a clear separation between
stuff that has (side-) effects (i.e. depends on the real word) and pure
functions (which don't). Abandoning global variables gives you a clear
separation of stuff that depends on initialized state and other stuff that
does not depend on it.

> Maybe I'm missing something, but this doesn't seem very attractive to me
> as a library writer (it means I must expose realInit and just trust
> users to only use it once).

Your realInit is an IO action, right?

Imagine you are a library user, and the library exports some IO action for
 you to use. Would you assume that it makes no difference whether you call it
 once or twice in the program?

Surely you won't: You know that IO actions have (side-) effects, so you would
take care that the actions get executed as many times as is apropriate. If
the library docs indicate that it makes no sense to call it twice, why would
you do so?

Maybe *I* am missing something, but I can't see any principle difference
between exporting 'realInit' and exporting 'putString'. In both cases the
program behaves differently depending on whether I call it once or twice.

> It doesn't seem very attractive to users either
> (considerably complicates their code and places the burden on them to
> "get it right").

It may seem so at first, but I think it's a delusion.

I found out with the HWS, that it does *not* necessarily "considerably
complicate" the (user) code. And the compiler helps you a lot to "get it
right", much more in fact than if you hide state dependency inside global
variables. In the above example, the compiler *forces* you to call
'YourModule.init' because it is the only way to produce a 'handle' and you
need some 'handle' to call the routines that depend on it. It also forces you
to call it *before* you use any of the routines that depend on it. All in all
this lifts a lot of the burdon off the user, rather than placing it on her.

At the moment I cannot imagine a well designed library interface where user
code would be considerably complicated if no global variables were used. But
maybe you have a good example at hand to prove that this is merely due to
lack of imagination on my side, and that I was extremely lucky with the
HWS? ;-)


More information about the Haskell mailing list