Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell FFI: Interfacing with simple C++?

Tags:

c++

haskell

ffi

From what I've read so far, using the FFI with C++ is very hard to accomplish. One of the biggest reasons seems to be converting C++ objects to Haskell. My problem now is that I don't have any experience with C, but a few years with C++, and also I prefer OOP. Therefore, I would naturally like to benefit from C++.

So can I write C++ programs designed to be used by the Haskell FFI to get around these problems? C++ could do anything under the hood, but the API would be C-like, i.e. I'm not exchanging objects, don't have overloaded top-level functions and so on. Are there any pitfalls to look out for?

(To compare my project with something you may be familiar with: Think of using SciPy's Weave to speed up Python code.)

like image 529
David Avatar asked Sep 18 '12 11:09

David


1 Answers

Yes, you can use C++ code via the FFI if you expose a C API on top of that C++ code.

A common pattern is to simply wrap all of a class's "methods" as C procedures, such that objects of that class can be treated as opaque pointers that those functions can be applied to.

For example, given the code (foo.h):

class foo
{
public:
  foo(int a) : _a(a) {}
  ~foo() { _a = 0; } // Not really necessary, just an example

  int get_a() { return _a; }
  void set_a(int a) { _a = a; }

private:
  int _a;
}

...you can easily create C versions of all of these methods (foo_c.h):

#ifdef __cplusplus
typedef foo *foo_ptr;
extern "C"
{
#else
typedef void *foo_ptr;
#endif

foo_ptr foo_ctor(int a);
void foo_dtor(foo_ptr self);

int foo_get_a(foo_ptr self);
void foo_set_a(foo_ptr self, int a);
#ifdef __cplusplus
} /* extern "C" */
#endif

Then, there must be some adapter code that implements the C interface via the C++ interface (foo_c.cpp):

#include "foo.h"
#include "foo_c.h"

foo_ptr foo_ctor(int a) { return new foo(a); }
void foo_dtor(foo_ptr self) { delete self; }

int foo_get_a(foo_ptr self) { return self->get_a(); }
void foo_set_a(foo_ptr self, int a) { self->set_a(a); }

The header foo_c.h can now be included in a Haskell FFI definition.

like image 82
dflemstr Avatar answered Nov 13 '22 14:11

dflemstr