Proposal: split Chan and TChan into read and write ends

Brandon Simmons brandon.m.simmons at
Sat Oct 27 05:23:09 CEST 2012

Hi everybody,
Just discovered all the great discussion here, and although my
google-fu turned up no prior discussions on this subject, I apologize
if it has already been discussed.

I propose that Chan and TChan should be implemented as a pair of read
and write ends, initialized as follows:

    newSplitChan :: IO (InChan a, OutChan a)

I've implemented this already here: . You can ignore the
type classes I've defined; they're there for my own reasons and not
part of the proposal.

Here is my best defense:

1) My own (and I assume others') use of Chans involves some bits of
code which do only reads, and others which do only writes; a split
implementation lets us use the type-checker to allocate read or write
"permissions" when we pass around either end, and generally makes
things easier to reason about. Others have independently reached this
conclusion as well.

2) The API is simpler (and in the case of TChans *much* simpler) with
a split approach; some examples: in TChan the types of the 'duplicate'
functions actually suggest (IMHO) the details of how they treat
existing messages, and require a less roundabout explanation

    dupTChan :: InTChan a -> STM (OutTChan a)
    cloneTChan :: OutTChan a -> STM (OutTChan a)

another example, 'newBroadcastTChan' is actually just:

    -- | Create a new write end of a TChan. Use dupTChan to get an
OutChan that values can be read from.
    newInTChan :: STM (InTChan a)

and doesn't require any explanation beyond that.

3) It's trivial to modify the *Chan libs in this way with a few edits
(really, they're already implemented this way, but with some added
contortions to return both a read and write end for each operation),
so there're no new tricky concurrency issues to reason about.

4) Values written to the write end can be reliably GC'd when readers
go away, although recent GHC seems to be able to do this on the
current implementation with -O2 on my simple tests.

5) While this is a big API change, I imagine the vast majority of
users would only have to change a few type signatures and the Chan
initialization action. An `OldChan` module could easily be implemented
in terms of the new split version. Alternatively, a *Chan.Split module
could be added, and the current Chan module defined in terms of it.

So two weeks of discussion?

Thanks all,

More information about the Libraries mailing list