Haskell's missing mutable reference type
In fact, it seems to me that this is the crux of it: rather than a thread-local variable, it’s a thread-and-children-local-variable. The “scoped” part of your proposal can be achieved by just forking a child thread before doing the modification!
This was wrong - you probably don’t want modifications by child threads to be seen in parent threads! So perhaps what you need is:
- A thread-local mutable variable;
- Child threads have their value initialized to the parent’s value when they are forked
I’m skeptical. Can you share an example?
It’s not quite your example, but here’s a common thing you do with a logging library.
loggerExampleConcurrently :: IO ()
loggerExampleConcurrently = withStdoutLogger 0 $ \logger -> do
logMsg logger 1 "Getting user"
user <- getUser
(d, ()) <-
Control.Concurrent.Async.concurrently
( setDomain logger "datafetch $ do
logMsg logger 0 "Getting data"
d <- getData user
Control.Concurrent.Async.forConcurrently d.transactions \t -> do
-- what's the domain here?
logMsg logger 0 "Getting data"
getTransaction t
)
( -- Do some unimportant background processing
do
Control.Concurrent.threadDelay 1000
logMsg logger 0 "Background work done"
)
writeTransactions d
logMsg logger 0 "Done"
We would want the log domain to be “datafetch” inside the nested concurrent map, but not in the adjacent concurrent processing. See e.g. the various local functions on MonadLog: Log.Class
As you point out in your other article, the example of existing functionality that works this way (thread masking state) also has the property of being inherited by child threads.
I also think it’s just quite intuitive: new threads are “lexically” inside the body of the modification, isn’t it natural that they see it?
Discussion in the ATmosphere