Safe use of unsafeCoerce?

Duncan Coutts duncan.coutts at worcester.oxford.ac.uk
Sat Apr 24 18:38:22 EDT 2004


All,

I'm after advice on whether the following example is a safe use of
unsafeCoerce, and if it is safe, if it's worth it.

In summary, if the following is ok:

castFooToBar :: Ptr Foo -> Ptr Bar
castFooToBar = castPtr

then is the following ok?

newtype Foo' = Foo' (Ptr Foo)
newtype Bar' = Bar' (Ptr Bar)

castFooToBar' :: Foo' -> Bar'
castFooToBar' = unsafeCoerce

Here's the context/motivation:
In the gtk2hs bindings for Haskell we model Gtk's object hierarchy by  a
hierarchy of Haskell classes and corresponding instances (and newtypes
of ForeignPtrs). Here's the pattern:

--The base class:
newtype GObject = GObject (ForeignPtr GObject)

mkGObject = GObject
unGObject (GObject o) = o

class GObjectClass o where
  toGObject   :: o -> GObject
  fromGObject :: GObject -> o

instance GObjectClass GObject where
  toGObject   = id
  fromGObject = id


--A derived class
newtype Widget = Widget (ForeignPtr Widget)

mkWidget = Widget
unWidget (Widget o) = o

class GObjectClass o => WidgetClass o

toWidget   :: WidgetClass o => o -> Widget
toWidget   = fromGObject . toGObject

fromWidget :: WidgetClass o => Widget -> o
fromWidget = fromGObject . toGObject

instance WidgetClass Widget

instance GObjectClass Widget where
  toGObject   = mkGObject.castForeignPtr.unWidget
  fromGObject = mkWidget.castForeignPtr.unGObject


So you can see in the instance of Widget for the GObjectClass we're
basically doing a pointer cast (and wrapping & unwrapping newtypes). In
C they just cast pointers. I'm wondering if we can do the same, ie
define the instance like so:

instance GObjectClass Widget where
  toGObject   = unsafeCoerce
  fromGObject = unsafeCoerce

Of course there's not much point, but if we know that toGObject &
fromGObject are just doing a cast, then we can get rid of the class
methods on GObjectClass and just implement them as ordinary class
constrained functions:

toGObject   :: GObjectClass o => o -> GObject
toGObject = unsafeCoerce

fromGObject :: GObjectClass o => GObject -> o
fromGObject = unsafeCoerce

So, the point is we can remove entirely the class dictionary that
otherwise has to be carried round for every object and the upcasting &
downcasting functions no longer need to do slow dictionary lookups when
all they are really doing is casting C pointers.

So is it a) safe? b) kosher?

BTW I know fromGObject is doing an unchecked downcast, it is only used
internally, we have safe checked ones that we expose in the interface.

Duncan



More information about the Glasgow-haskell-users mailing list