[Haskell-cafe] dangerous inlinePerformIO in Data.Binary(?)

Roberto Zunino zunino at di.unipi.it
Sun Jun 17 12:06:03 EDT 2007

Udo Stenzel wrote:
> | toLazyByteString :: Builder -> L.ByteString
> | toLazyByteString m = S.LPS $ inlinePerformIO $ do
> |     buf <- newBuffer defaultSize
> |     return (runBuilder (m `append` flush) (const []) buf)
> Why is this safe?  Considering the GHC implementation of IO, isn't there
> a real danger that 'newBuffer defaultSize' is floated out and therefore
> every invocation of 'toLazyByteString' starts out with the same buffer?

Floating out (newBuffer defaultSize) as in

| foo = newBuffer defaultSize
| toLazyByteString m = S.LPS $ inlinePerformIO $ do
|     buf <- foo
|     return (runBuilder (m `append` flush) (const []) buf)

would still be safe, AFAICS. Floating out buf instead should be 
prevented by the implicit RealWorld parameter.

My (possibly wrong) understanding is that, each invocation of 
(toLazyByteString m) may cause either
1) a new buf to be allocated and runBuilder run on it or
2) to reuse the result of another invocation of (toLazyByteString m), 
having the same m

Case 1) would be the "no inlining happened" case, while 2) would be
the "inlining happened". So, the buf stored in S.LPS may be equal for 
equal m's. Different m's should use distinct buffers.


More information about the Haskell-Cafe mailing list