Should we have primitive fill-once variables?

David Feuer david at well-typed.com
Fri Jun 29 16:54:23 UTC 2018


On Friday, June 29, 2018 11:51:07 AM EDT Joachim Breitner wrote:
> when reading the subject I was expecting something like this:
>
>    -- | pure! but blocks until the IVar is written
>    readIVar :: IVar a -> a 
>
>    -- | tries to write to an IVar. 
>    -- Succeeds if it is empty (returning True)
>    -- Does nothing if it has been written to (returning False)
>    writeIVar :: IVar a -> a -> IO Bool

It really depends. Are there useful (compile-time or run-time) optimization for IVars (write-once) that don't apply to QVars (fill-once)? If so, we might indeed want to offer writeIVar as you suggest, and

> readIVar :: IVar a -> (# a #)

The unboxed tuple allows the value to be extracted from the IVar without being forced. If, however, we want QVars, we can always simulate that using accursedUnutterablePerformIO:

> readIVarPure (IVar var) = case readIVar# var realWorld# of (# _, a #) -> (# a #)

I don't know if there are useful IVar optimizations or not. If so, we should take them; if not, we should take the extra flexibility.

> Alternatively:
> 
>    -- | all in one
>    newIVar :: IO (a, a -> IO Bool)

Does this have some advantage as a primop?

> In fact, people have implemented something like this using C-- hacks
> before: https://github.com/twanvl/unsafe-sequence

I'll have to take a look.

> > This would make MonadFix's implementation much nicer, I think :)
> 
> This would suffice for MonadFix, right?

It should indeed.

Side note: my implementation sketch for readQVar was missing one piece: after a reader pushes itself on the stack, it must check the QVar status a second time in case the QVar was filled between the read and the enstackment. If it's been filled, it needs to awaken the first thread the way writeQVar would. Indeed, it might as well check the QVar status on every trip through the CAS loop.


More information about the ghc-devs mailing list