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? ;-) Cheers, Ben _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell