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