Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve C++ support #13

Open
bitonic opened this issue May 6, 2015 · 5 comments
Open

Improve C++ support #13

bitonic opened this issue May 6, 2015 · 5 comments

Comments

@bitonic
Copy link
Collaborator

bitonic commented May 6, 2015

The main things to do are:

  • Facilitate memory management by attaching the right finalizers to C objects;
  • Facilitate the handling of pointers pointing to C++ types from Haskell.

I have some ideas for both, currently experimenting.

@mboes
Copy link
Contributor

mboes commented May 20, 2015

Writing down those ideas would help others pick this up if they want to.

@chpatrick
Copy link
Contributor

An idea for template support:

Anything with template polymorphism would be generated with an explicit function. This function would get a templated C++ implementation and a Haskell typeclass. You could then request specializations of this function for given Haskell types, which would produce typeclass instances.

Sketch:

data Vector a

[temp| {class PushBack a}
template <class $a>
void pushBack(const vector<$a> *foo), $a val) {
  foo->push_back(val);
} |]

[tempInst| pushBack<int> |]

[tempInst| pushBack<char*> |]

... generates Haskell

class PushBack a where
  pushBack :: Ptr (Vector a) -> a -> IO ()

foreign import ccall inline_c_pushBack_cInt ...

instance PushBack CInt where
  pushBack = inline_c_pushBack_cInt

foreign import ccall inline_c_pushBack_cChar_ptr ...

instance PushBack (Ptr CChar) where
  pushBack = inline_c_pushBack_cChar_ptr

and C++

template <class inline_c_a>
void pushBack(vector<inline_c_a> *foo), inline_c_a val) {
  foo->push_back(val);
}

extern "C" {
  static void inline_c_pushBack_cInt(vector<int> *foo, int val) {
    pushBack<int>(foo, val);
  }

}

etc..

@chpatrick
Copy link
Contributor

Actually you could just use a regular block instead of a function, and you could share classes:

pushBack :: VectorImpl a => Ptr (Vector a) -> a -> IO ()
pushBack vec val =
  [block| <class VectorImpl a> void { 
    $(vector<$type:a> *vec) ->push_back($($type:a val));
  |]

resize :: VectorImpl a => Ptr (Vector a) -> Int -> IO ()
resize vec size =
  [block| <class VectorImpl a> void { 
    $(vector<$type:a> *vec) ->resize($(int val));
  |]

destruct :: VectorImpl a => Ptr (Vector a) -> IO ()
destruct vec =
  [block| <class VectorImpl a> void { 
    delete $(vector<$type:a> *vec);
  |]

[tempImpl| VectorImpl CInt |]

produces:

class VectorImpl a where
  inline_c_pushBack_32193293 :: Ptr (Vector a) -> a -> IO ()
  inline_c_resize_3232112131 :: Ptr (Vector a) -> Int -> IO ()
  inline_c_destruct_43244234 :: Ptr (Vector a) -> IO ()

instance VectorImpl CInt where
  ...

@bitonic
Copy link
Collaborator Author

bitonic commented Jul 6, 2015

Yes, that makes a lot of sense, thanks a lot for the input. I especially like the second mockup of how it would look like.

There is the slight disadvantage of an upfront setup, but I don't think we can do much better than that.

I fear that the hardest part of this will be parsing C++ types...

@chpatrick
Copy link
Contributor

Some further thoughts:

It would be good if external modules could generate implementations of templating classes (eg. VectorImpl above). This means they need access to the source of the templated C++ functions. It would be quite a pain to include the generated code from another module, so as a (slightly out there) alternative I propose that we encode the necessary information as an instance of a type family on these template typeclasses. This could then be recovered in TH in the external module and included with the template specializations.

data ClassImpl str = ClassImpl { templateSources :: [ ( str, str ) ] }
type family Template (cls :: k) :: ClassImpl Symbol
type instance Template VectorImpl
  = 'ClassImpl
    '[ '( "inline_c_pushBack_0", "template<class T>..." )
     ]

Or perhaps when we produce a templating class, eg. VectorImpl, we could also produce a function createVectorImpl :: Name -> DecsQ that could be called in other modules when specialization is required. Or have an intermediate step and have functions:

defVectorImpl :: Name -> TemplateClassInfo -- generated with VectorImpl
tempImpl :: TemplateClassInfo -> DecsQ -- in inline-c

and then it's tempImpl $ defVectorImpl ''CInt at the use site.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants