Git Product home page Git Product logo

Comments (10)

aspiwack avatar aspiwack commented on August 25, 2024

I gather that the problem that you are highlighting is solely on the IO implementation? Or does the same happen with, say StateT Maybe?

What behaviour would you expect in case or errors?

from capability.

re-xyr avatar re-xyr commented on August 25, 2024

Sorry - I was mainly thinking about the situation for ReaderT IO (and my mind didn't work very well yesterday), where I would expect a bracket over the m. This can be provided as a separate strategy on monads with MonadMask.

I'm not entirely sure with the semantics in the case of using a transformer stack, but I can imagine something like this going wrong:

data M a = M { runM :: ExceptT () (State String) a }
  deriving (Functor, Applicative, Monad, Mtl.MonadState String, Mtl.MonadError ())
  deriving (HasSink "log" String, WriterLog "log" String)
    via SinkLog (MonadState M)
  deriving (HasThrow "err" ())
    via MonadError m

f :: (Either () String, String)
f = runState (runExceptT $ runM $ tell "a" *> listen (tell "b" *> throw () *> tell "c")) ""

-- Expected: (Left (), "ab")
-- Actual: (Left (), "b")

disclaimer - I don't have my machine near me, and i haven't tested this. Feel free to ignore before I get home and do some experiment.

from capability.

aherrmann avatar aherrmann commented on August 25, 2024

The concurrency problem may not be worth fixing (in some sense), but at least it deserves a warning in the docs

HasState, same as MTL's MonadState, is not concurrency safe. In particular modify' is implemented as

 do s <- get
    put $! f s

which is not atomic.

having no error recovery is arguably a larger problem.

This issue about HasMask seems relevant to this question. I imagine that an exception safe version of this would require a bracket of some sort.

from capability.

aspiwack avatar aspiwack commented on August 25, 2024

We could, presumably, implement modify' using state, though. And implement state with modifyRef, though this is not atomic on IORef by default (which uses modifyIORef, rather than atomicModifyIORef.

That being said, I suppose that get >>= put is safe with MVars, so maybe we simply don't have to care about the concurrency part.

from capability.

aherrmann avatar aherrmann commented on August 25, 2024

That being said, I suppose that get >>= put is safe with MVars, so maybe we simply don't have to care about the concurrency part.

Hmm, I might be misreading, but I don't see how. The following kind of interleaving is the issue I'm referring to, where modify' is not atomic.

do s1 <- get     |
                 |  do s2 <- get
   put $! f1 s1  |
                 |     put $! f2 s2

We could, presumably, implement modify' using state, though.

Can we? modify' still needs to be strict in the MTL MonadState case, where state is just the underlying MTL state. And, I presume, in general modify (without ') should still be non-strict.

from capability.

re-xyr avatar re-xyr commented on August 25, 2024

(Guessing) For MVars, it is possible that we implement modify with takeMVar and putMVar in combination which will be atomic, since any other thread trying to read will be blocked. Apparently that is different from get >>= (put . f) though.

from capability.

aspiwack avatar aspiwack commented on August 25, 2024

Hmm, I might be misreading, but I don't see how. The following kind of interleaving is the issue I'm referring to, where modify' is not atomic.

On MVar that interleaving will just have s2 block on get (well, unless get is implemented as readMVar rather than takeMVar… which it probably is. Grumble.)

Can we? modify' still needs to be strict in the MTL MonadState case, where state is just the underlying MTL state. And, I presume, in general modify (without ') should still be non-strict.

It probably depends how state is implemented. If the pair is used lazily (fst, snd), then we can't quite make it strict for State. An alternative is to add a strict state' primitive to the class.


But maybe we should focus on the behaviour with exception first.

from capability.

aherrmann avatar aherrmann commented on August 25, 2024

On MVar that interleaving will just have s2 block on get (well, unless get is implemented as readMVar rather than takeMVar… which it probably is. Grumble.)

get indeed uses readMVar, and it has to, because sequencing get, e.g. get >> get, is allowed by the state API and is not expected to block indefinitely.

My impression is that MonadState and thereby HasState, which is based on the former, is just not designed for a concurrent use-case.

I believe we discussed a potential HasAtomicState that could be designed for that use-case at some point in the past.


But maybe we should focus on the behaviour with exception first.

Agreed. Coming back to HasMask, we could make such a capability a prerequisite of the WriterLog instance. If needed we could provide the simpler UnmaskedWriterLog without such a constraint.

from capability.

re-xyr avatar re-xyr commented on August 25, 2024

a potential HasAtomicState

What about introducing get_ and put_ as methods of HasState too, allowing different semantics of get >>= put and state? Three operations can all be atomic, and modify can be defined in terms of state (thus also atomic).

from capability.

aherrmann avatar aherrmann commented on August 25, 2024

a potential HasAtomicState

What about introducing get_ and put_ as methods of HasState too, allowing different semantics of get >>= put and state? Three operations can all be atomic, and modify can be defined in terms of state (thus also atomic).

They are methods of HasState's super-classes HasSource and HasSink already.

An advantage of a dedicated class would be that atomicity could be specified on the class, such that all instances must fulfill it. Meaning, all code using HasAtomicState would be correct in a concurrent use-case. The trouble with making this a property of particular instances is that, in that case, code that is written with the constraint HasState => ... might not be correct for some instances of HasState.

from capability.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.