
At 2001-08-09 03:01, Simon Marlow wrote:
I considered providing a different API for bidirectional streams, or perhaps requiring that bidirectional streams use separate Handles for read and write, but came to the conclusion that the user really doesn't care whether under the hood a single Handle is using separate buffers for read and write or just a single buffer, how much locking is going on or whatever. The fact that these things are awkward to implement shouldn't show through in the library interface.
It's definitely more convenient from the programmer's point of view to be able to use the *same* handle object for both read and write, otherwise you have to explain to people why they can have a read/write file handle but not a read/write handle for a TCP socket.
Well, how about something like this: -- type TCPPortNumber = Word16 type IPAddress = Word32 data TCPPort = MkTCPPort IPAddress TCPPortNumber data TCPSocket = ... openTCP :: TCPPort -> IO TCPSocket closeTCP :: TCPSocket -> IO () listenTCP :: TCPPortNumber -> (TCPConnection -> IO ()) -> IO () -- not sure about listenTCP getRemoteAddressTCP :: TCPSocket -> IO TCPPort getLocalAddressTCP :: TCPSocket -> IO TCPPort receiveTCP :: TCPSocket -> Integer -> Integer -> IO (Maybe [Word8]) -- "receiveTCP socket waittime arraylength" -- return "Nothing" if received end with no octets pending -- return "Just array" where array is as many octets up to length as received by waittime -- set waittime to 0 to not wait but return only available bytes in buffer. receiveWaitForeverTCP :: TCPSocket -> Integer -> IO (Maybe [Word8]) -- Same, with infinite wait-time. -- only useful if it can be interrupted by another thread sendDataTCP :: TCPSocket -> [Word8] -> IO () sendEndTCP :: TCPSocket -> IO () -- OK, this is just off-the-cuff and probably has many flaws, and I offer it merely for discussion, not as a proposal. It does, however, represent the kind of basic functionality I'd look for, or abstract, if writing a TCP application. If programmers want to abstract away the differences between different types of network connections, well, this is Haskell so they can always write classes like this: -- class (Monad m) => Closable s m | s -> m where close :: s -> m () class (Monad m) => Source s m d | s -> m d where read :: s -> Integer -> Integer -> m (Maybe [d]) readWaitForever :: s -> Integer -> m (Maybe [d]) class (Monad m) => Sink s m d | s -> m d where writeData :: s -> [d] -> m () writeEnd :: s -> m () write s Nothing = writeEnd s write s (Just d) = writeData s d -- etc. -- Ashley Yakeley, Seattle WA