[Haskell] thread-local variables

Frederik Eaton frederik at a5.repetae.net
Fri Aug 4 12:29:36 EDT 2006


> As for the subject under discussion (thread local state), I am
> personally sceptical about it. Why do we need it? Are we talking
> about safety or just convenience/API elegance? I've never
> encountered a situation where I've needed thread local state,
> (but this does not necessarily make it evil:-)

OK. What if all Haskell processes, all over the world, were made into
threads in the same large process? There are a lot of things that are
currently "global" state - as in, process-global - which would have to
become non-global in some way - pretty much all interaction with the
world: file IO, networking, command line arguments, system
environment, etc.

You, Einar, and others seem to be arguing that the only way to make
these things non-global should be to either make them explicit
arguments to functions, or to have them appear explicitly in the type
of the application's primary monad.

For instance, this simple program:

main :: IO ()
main = do
    putStrLn "Hello world"

might, in Adrian Hey and Einar Karttunen's world, become:

newMain host environment program_args
    network_config locale terminal_settings
    stdin stdout stderr = do
    hPutStrLn stdout (defaultEncoding locale) "Hello world"

Now, some people might find this second version delightfully explicit,
but I'd have doubts about whether such people are actually trying to
get things done, or whether they see the language as an end in itself. 
As for me, I prefer the first version - it saves reading and typing,
and is perfectly clear, and I have work to do.

Maybe I'm misunderstanding your position - maybe you think that I
should use lots of different processes to segregate global state into
separate contexts? Well, that's nice, but I'd rather not. For
instance, I'm writing a server - and it's just not efficient to use a
separate process for each request. And there are some things such as
database connections, current user id, log files, various profiling
data, etc., that I would like to be thread-global but not
process-global.

Or maybe you think that certain types of global state should be
privileged - for instance, that all of the things which are arguments
to 'newMain' above are OK to have as global state, but that anything
else should be passed as function arguments, thus making
thread-localization moot. I disagree with this - I am a proponent of
extensibility, and think that the language should make as few things
as possible "built-in". I want to define my own application-specific
global state, and, additionally, I want to have it thread-global, not
process-global.

You asked for an example, but, because of the nature of this topic, it
would have to be a very large example to prove my point. Thread-local
variables are things that only become really useful in large programs. 
Instead, I've asked you to put yourself in my shoes - what if the bits
of context that you already take for granted in your programs had to
be thread-local? How would you cope, without thread-local variables,
in such a situation?

> But I would say that I think I would find having to know what thread
> a particular bit of code was running in in order to "grok it" very
> strange,

I agree that it is important to have code which is easy to understand.

Usually, functions run in the same thread as their caller, unless they
are passed to something with the word 'fork' in the name. That's a
good rule of thumb that is in fact sufficient to let you understand
the code I write. Also, if that's too much to remember, then since I'm
only proposing and using non-mutable thread-local state (i.e. it
behaves like a MonadReader), and since I'm not passing actions between
threads as Einar is, then you can forget about the 'fork' caveat.

I think the code would in fact be more difficult to "grok", if all of
the things which I want to be thread-local were instead passed around
as parameters, a la 'newMain'. This is simply because, in that
scenario, there would much more code to read, and it would be very
repetitive. If I used special monads for my state, then the situation
would be only slightly better - a single monad would not suffice, and
I'd be faced with a plethora of 'lift' functions and redefinitions of
'catch', as well as long type signatures and a crowded namespace.

> unless there was some obvious technical reason why the
> thread local state needed to be thread local (can't think of any
> such reason right now).

Some things are not immediately obvious. If you don't like to think of
reasons, then just take my word for it that it would help me. A
facility for thread-local variables would be just another of many
facilities that programmers could choose from when designing their
code. I'm not asking you to change the way you program - I don't care
how other people program. I trust them to know what is best for their
particular application. It's none of my business, anyway.

Since Simon Marlow said that he had been considering a thread-local
variable facility, I merely wanted to voice my support:

http://www.mail-archive.com/haskell@haskell.org/msg18398.html

It seems that there are enough resources to implement one. The
discussion should not be about "do we allow this" but rather "what
should the API be".

Frederik

-- 
http://ofb.net/~frederik/


More information about the Haskell mailing list