proposal: add 'unsafeCoerce'

Donald Bruce Stewart dons at cse.unsw.edu.au
Mon Nov 20 00:51:29 EST 2006


dons:
> iavor.diatchki:
> > Hello,
> > I think that it is a really bad idea to make 'unsafeCoerce' a part of
> > the standard libraries.  As far as I understand, 'unsafeCoerce' is
> > only "safe" if the programmer assumes something about the
> > representations of values (in particular, that values of different
> > types have the same representations).  Haskell makes no such
> > guarantees so, by definition, any program that uses 'unsafeCoerce' is
> > using an implementation specific extension.  I was trying ot think of
> > cases where 'unsafeCoerce' might be somewhat safe, and the main
> > example I came up with is when the coersion happens on a phantom type.
> > Are there other reasonably portable examples?

A quick grep in the core libraries, for insight:

FFI stuff:

    ./base/Data/Array/Base.hs:678:
            nullStablePtr = StablePtr (unsafeCoerce# 0#)
    ./base/Data/Array/Base.hs:1522:    
            case unsafeCoerce# memcpy marr'# marr# n# s2# of { (# s3#, () #) ->
    ./base/Data/Array/Base.hs:1592:    
            case unsafeCoerce# memcpy marr# arr# n# s2# of { (# s3#, () #) ->
    ./base/Data/Array/Base.hs:1657:    
            return (STUArray l u (unsafeCoerce# marr#))

Equalities not expressible in the type system:

    ./base/Data/Dynamic.hs:124:
            toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
    ./base/Data/Dynamic.hs:135:  
            | typeOf def == t = unsafeCoerce v
    ./base/Data/Dynamic.hs:147:  
            case unsafeCoerce v of 
    ./base/Data/Dynamic.hs:155:    
            Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x))
    ./base/Data/Typeable.hs:452:               
            then Just $ unsafeCoerce x
    ./base/Data/Typeable.hs:460:        
            then Just $ unsafeCoerce x
    ./base/Data/Typeable.hs:470:       
            then Just $ unsafeCoerce x
    ./base/Data/Typeable.hs:480:       
            then Just $ unsafeCoerce x

I was actually surprised to see. That could be removed I'm pretty sure:

    ./base/Data/ByteString/Char8.hs:304:
            go :: Addr# -> [Char] -> ST a ()
            go _ []        = return ()
            go p (C# c:cs) = writeByte p (unsafeCoerce# c) >> go (p `plusAddr#` 1#) cs

And some GHC things

    ./base/GHC/Handle.hs:1661:
            puts s = do write_rawBuffer 1 (unsafeCoerce# (packCString# s)) 0 (fromIntegral (length s))

    ./base/GHC/ForeignPtr.hs:159:	     
            (# s, ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
    ./base/GHC/ForeignPtr.hs:171:       
            (# s, ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
    ./base/GHC/ForeignPtr.hs:193:             
            (# s, ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
    ./base/GHC/ForeignPtr.hs:205:       
            (# s, ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
    ./base/GHC/ForeignPtr.hs:318:
            castForeignPtr f = unsafeCoerce# f

And some FFI binding stuff:

    ./ObjectIO/Graphics/UI/ObjectIO/Process/IOState.hs:139:		
            | ioStGetIOId ioSt == id = unsafeCoerce# (ps, ioSt)
    ./ObjectIO/Graphics/UI/ObjectIO/Window/Access.hs:578:	
            | identifyWIDS wid wids = Just (unsafeCoerce# ls)

So the uses fall into 2 categories:

  * FFI binding and raw pointer/foreign data manipulation
  * type equalities known, but not expressible statically

Now, can we say something portable about these uses?

-- Don


More information about the Libraries mailing list