[Haskell-cafe] Re: Global variables again

Benjamin Franksen benjamin.franksen at bessy.de
Tue Nov 23 08:08:49 EST 2004

[we should really keep this on haskell-cafe because such lengthy discussions 
are what the cafe is for]

On Tuesday 23 November 2004 10:26, Adrian Hey wrote:
> On Monday 22 Nov 2004 4:03 pm, Benjamin Franksen wrote:
> > This is getting ridiculous. At least two workable alternatives have been
> > presented:
> >
> > - C wrapper (especially if your library is doing FFI anyway)
> > - OS named semaphores
> Neither of these alternatives is a workable general solution.

Since the problem only appears in special situations, a general solution is 
not required, nor is it desirable (because of the danger of infection with 
the "global variable disease".)

> There are several significant problems with both, but by far
> the most significant problem (at least if you believe that top
> level mutable state is evil) is that they both rely on the use
> of top level mutable state. If this is evil it is surely just as
> evil in C or OS supplied resources as it is in Haskell.

The evil is in the world in the form of C libraries with hidden global 
variables and hardware with non-readable registers.

What I am arguing for is to *contain* this disease by forcing a solution to 
happen outside of Haskell.

What you are arguing for (i.e. a general solution *in* Haskell) amounts to 
(deliberately) *spreading* the disease.

> The fact that one solution requires the use of a completely different
> programming language 

And that is exactly the point: In order to do evil you have to go somewhere 
else, preferably to where the problem originally came from. If it originated 
in C, go fix it on the C level. If originates in the OS, go fix it on the OS 
level. As for broken hardware, you should use a OS level mechanism, so that 
multiple initialization is prevented OS wide and not only per program run.

> and the other requires the use of a library which 
> could not be implemented in Haskell (not without using unsafePerformIO
> anyway) must be telling us that there something that's just plain missing
> from Haskell. 

Yes it's plain missing and for good reasons. There are many things plainly 
missing from Haskell besides global variables.

> IMO this is not a very satisfactory situation for a language 
> that's advertised as "general purpose".

"General purpose" doesn't mean that any programming idiom is supported.

> > Further, as for "evidence or credible justification" for the my claim,
> > you can gather it from the numerous real-life examples I gave, and which
> > you chose to ignore or at least found not worthy of any comment.
> I have no idea what examples you're talking about. Did you post any code?

No, I didn't post code. I already said it's annecdotal evidence. For instance, 
I was talking about using the ONC/RPC implementation on VxWorks, which is 
broken because they internally use thread-local mutual state.

> If so, I must have missed it for some reason. Perhaps your're refering
> to your elimination of unsafePerformIO from a library you were writing.

I wasn't.

> > Of course,
> > these examples are only annecdotal but I think this is better than a
> > completely artificial requirement (like your "oneShot").
> Being able to avoid the use of top level mutable state sometimes (or even
> quite often) is not proof that it's unnecessary, 

True. I have never claimed that, though. What I claimed is that in the cases 
where they are necessary, FFI is probably used anyway, so it *is* workable to 
use a foreign language wrapper.

In order to convince me that this is wrong you could present a (real-world, no 
artificial requirements) example that does not require the use of FFI anyway. 
If you can do so (which I doubt) I might be willing to accept a 
compiler-supported standard library routine with a very long and very ugly 
name like

warningBadStyleUseOnlyIfAbolutelyNecessary_performOnlyOnce: IO a -> IO a


> especially when nobody 
> (other than yourself presumably) knows why you were using it in the first
> place. 

Not I. And it was for convenience only, as I proved by completely eliminating 
them without making the code any more complicated. I never claimed that this 
proves anything, it was just a personal experience.

BTW, the main reason they use global variable in C all the time is because 
it's just so damn convenient (at first) and *not* because there are problems 
otherwise unsolvable. (There are *very* few exceptions.)

> However, the existance of just one real world example where it does 
> appear unavoidable is pretty convincing evidence to the contrary IMO.

I agree that the alternatives are not a good *general* solution. I have been 
arguing that a general solution is not desirable.

> > You have been asked more than once to present a *real-life* example to
> > illustrate that
> >
> > (a) global variables are necessary (and not just convenient),
> > (b) both above mentioned alternatives are indeed unworkable.
> I knew this would happen. I was asked to provide an example and I *did*.
> I gave the simplest possible example I had of the more general problem,
> and now this whole thread has consisted of either repeated denials of
> the reality of even this simple problem (something you've just done again)
> or protracted discussions over various half baked non-solutions to
> this one particular problem (such as those you identify above) without
> seeing the real underlying general problem.

There is no underlying problem, apart from interfacing evil hardware or 
foreign libraries. At least I know of none.

> > > You have yet to
> > > explain how you propose to deal with stdout etc..
> >
> > I see absolutely no reason why stdxxx must or should be top-level mutable
> > objects. They can and should be treated in the same way as environment
> > and command line arguments, i.e.
> >
> > getArgs :: IO [String]
> > getEnv :: String -> IO String
> > getStdin, getStdout, getStderr :: IO Handle
> >
> > Note that (just like environment and command line arguments) these
> > handles may refer to completely different things on different program
> > runs.
> Sure, Peter Simons suggested the same thing. I have no great objection,
> but why do this?

Strange. I told you the reason. You even cited it. What about reading it, 
too ;-?

> I mean what extra safety does this buy you?

Nobody claimed that global variables are unsafe in any strict sense.

> Anybody can  
> still get at stdout and write anything they like to it.

Sure they can. They have been warned, though... ;-)

> The only difference is that instead of writing..
>  do ...
>     foo stdout
>     ...
> ..they now have to write..
>  do ...
>     stdout <- getStdout
>     foo stdout
>     ...
> I don't see why the former should be regarded as a source of great evil
> which is somehow eliminated by the latter.

To repeat myself once again: The latter version makes it clear to anyone 
looking at the code, that the stdout above

(a) might refer to something different from other results of getStdout 
elsewhere in the program (e.g. stdout might have been closed or re-opened)

(b) might refer to completely different things on different program runs (e.g. 
output of program is piped to some other process or even a socket).

Top level things with identity are evil.	-- Lennart Augustsson

More information about the Haskell-Cafe mailing list