I'm writing a Haskell wrapper for a C++ class. I decided to represent it as a Haskell Data structure containing a pointer (Foreign.Ptr) to the class instance in C++. Something like that.
In C++:
class MyClass {
public:
double my_method();
// ...
};
extern "C" MyClass* cpp_new_MyClass() {
return new MyClass();
}
extern "C" double cpp_my_method(MyClass *obj) {
return obj->my_method();
}
In Haskell:
Data MyClass = MyClass (Ptr ())
foreign import ccall "cpp_new_MyClass" cppNewMyClass :: Ptr ()
foreign import ccall "cpp_my_method" cppMyMethod :: Ptr () -> Double
mkMyClass :: MyClass
mkMyClass = MyClass cppNewMyClass
myMethod :: MyClass -> Double
myMethod (MyClass ptr) = cppMyMethod ptr
The problem is, I don't know how to correctly implement MyClass deletion. At some point, Haskell garbage collector will delete MyClass object, but it won't trigger MyClass* memory freeing in C++. How do I fix that?
I'm aware of ForeignPtr, but it uses IO
monad, which is not satisfying because I want the wrapped data structure to behave exactly as a normal Haskell data structure, without the need for explicit allocating/freeing memory or IO
monads.
“it uses
IO
monad, which is not satisfying because I want the wrapped data structure to behave exactly as a normal Haskell data structure”
Sure you do, but unfortunately it's not really possible. Foreign “functions” can always do funny stuff that shouldn't be possible in Haskell; the type system has no way to look there and prevent it.
That dilemma is the only (!) reason we have unsafePerformIO
, and indeed yours is a good example of a valid application for that thing.
I haven't done this myself yet, but your code should look something like the following:
extern "C" void cpp_delete_MyClass(MyClass* obj) {
delete obj;
}
foreign import ccall "cpp_new_MyClass" cppNewMyClass :: IO (Ptr ())
foreign import ccall "&cpp_delete_MyClass" cppDeleteMyClass :: FunPtr (Ptr () -> IO ())
data MyClass = MyClass (ForeignPtr ())
mkMyClass :: MyClass
mkMyClass = unsafePerformIO $ do
newObj <- cppNewMyClass
fPtr <- newForeignPtr cppDeleteMyClass newObj
return $ MyClass fptr
I'm not quite sure about those FunPtr
s, hopefully somebody will comment something about that...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With