[Haskell] Re: Global Variables and IO initializers
ahey at iee.org
Sun Nov 7 16:55:25 EST 2004
On Sunday 07 Nov 2004 1:45 pm, Benjamin Franksen wrote:
> 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.
I don't agree. Hidden dependencies are a fact of life with stateful
programming in general and IO monad in particular. Making some
references explicit arguments (as you seem to be suggesting) does
not eliminate the problem, it merely complicates an api for no good
Hiding internal state dependencies is a *good thing*. The trick is
organise the dependencies and provide a robust "idiot proof" api so
that users don't have to know about the internal organisation and any
dependencies. I don't believe this is a new (or controversial) idea.
Its the basic idea behind stateful modular or OO programming.
All the user sees is a set of actions which collectively deliver on
a promise (by unknown means).
> > 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?
No, of course not.
> 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?
Given such a statement about realInit you wouldn't (or to be more precise,
given a statement that calling it twice or more will really screw things up).
But the question is *how* is the user to ensure that it is only called once.
I see no other way than the darned awkward alternative I gave. I suppose
the other alternative is the noddy realInit is only used once in an action
which is only used once, in an action .. from main (which is only used once
hopefully). Is this what you have in mind?
If so I don't see that as a viable option for anything but the simplest
programs, and even this assumes there are no other hidden uses of realInit
in any other libraries.
> 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.
Yes you are. Is this really your view? Or you just arguing for the sake
of it? The behaviour of (and consequent constraints on correct useage of)
realInit and putString are very different. Must I eloborate them?
> > 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.
Trust me on this, for whatever reason, it's absolutely vital that realInit
is used 0 or 1 times only, 2 or more is a catastrophic error.
So I'll ask again. Please provide a simpler _and_ safer alternative
(some real Haskell code please).
> 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? ;-)
Indeed, I believe this is the case. I'm guessing of course, but I imagine
all your IO is done via standard Haskell library calls (socket API
or whatever), in which case they will hide a lot of the stateful compexity
of their implementation already. If so it seems to me you're using the fact
that somebody has already solved the problem for you as an argument that
no solution is necessary. (It would be interesting to see what the api's
of the libraries you're using would look like, if they had been designed
according to the principles you're advocating).
More information about the Haskell