Banging My Head Against the Wall With Haskell and C++ FFI

Posted on 18th of December 2022 | 1747 words

As some of you may know, I have a soft spot for functional programming. So most of the code I tend to write outside my professional work tends to be written in Haskell!

Unfortunately, the world we live in is still living in a world of imperative languages, and due to the sheer amount of that code, we most likely will be living in that world for years to come; I can’t say forever since the planet is not here forever, but we’re talking about a long, long time. It’s also the same for my own professional life.

I’m not very fanatical when it comes to tooling as long as it gets the job done. But still, the interaction between imperative and functional worlds is fascinating. So we are talking about foreign function interface (FFI) here.

Lately, I’ve been banging my head against the wall with the FFI of Haskell since I wanted to write a particular piece of code in mainly Haskell, but I needed something from the world of C++. Could have I written this in just Haskell? Probably, but despite enjoying functional programming more over imperative code, certain data structures, algorithms and libraries work better in the C++ world and sometimes you might need to “extra oomph” when it comes to performance.

Okay, better is a strong word for this, maybe better on how they work in the imperative world and but they don’t translate one to one to fully functional and pure world of Haskell where there are better options for data structures and algorithms. Sure some libraries are only written in C++, so there is nothing that can be done with it. For functional data structures, I definitely recommend Purely Functional Data Structures by Chris Okasaki .

Generally speaking, when it comes to FFI, interacting with C is pretty straightforward, but when C++ comes into play, some extra ceremony is required due to the nature of the language with things like unstable ABI, more extensive language and more complex features. Thankfully, C++ offers an easy way to write C ABI compatible code with the extern "C" keyword, which makes it so that the code can be called from C. But there is a caveat in this. While you can use C++ features inside the function body, when you use extern "C" functions type signature needs to be compatible with C. So no fancy STL features etc., here.

Also, when we talk about C and/or C++, memory management comes into question. So if you want to bind those languages to some memory-managed language like Haskell, you need to ensure that the memory gets handled correctly. C++ offers fancy features like RAII, smart pointers and stuff for making memory management a little bit easier, but that’s not the case in C.

Let’s start by creating a small Cabal project and some sample C++ library that we would like to interact with from Haskell.

common base
  ghc-options: -Wall -Wextra -Wno-orphans -Wno-name-shadowing
  default-language: Haskell2010
  build-depends: base ^>=4.16.3.0

executable arith
  import: base
  main-is: Main.hs
  hs-source-dirs: app

  -- C++ bits
  cxx-options: -std=c++20 -Wall -Werror -Wextra
  cxx-sources: cbits/arith_capi.cc cbits/arith.cc
  include-dirs: cbits
  extra-libraries: stdc++

While otherwise, it’s a reasonably standard Cabal boilerplate, the interesting bits are the lines relating to C++. Basically, what we do here is define some compiler options for the C++ compiler, where the C++ source files are located, and the relevant header files. Commonly, in Haskell, if you’re library/application has had anything related to C or C++ files relevant for those have usually resided in a directory called cbits, but nothing forces you to follow this convention. When that’s done, we can proceed to write some “earth-shattering” C++ library for our application.

// arith.h

#pragma once

struct arith {
  arith() noexcept;

  int add(int x, int y) noexcept;
  int sub(int x, int y) noexcept;
  int mult(int x, int y) noexcept;
  int div(int x, int y) noexcept;
};
// arith.cc

#include "arith.h"

arith::arith() noexcept {}

int arith::add(int x, int y) noexcept { return x + y; }
int arith::sub(int x, int y) noexcept { return x - y; }
int arith::mult(int x, int y) noexcept { return x * y; }
int arith::div(int x, int y) noexcept { return x / y; }

We’ll just define a simple arith struct/class with some elementary arithmetic operations. Nothing too fancy. This will work as our C++ library that we’ll interact with via Haskell. After that’s done, we need to provide some simple C API for this library so that we can interact with the library via the stable C ABI.

// arith_capi.h

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

typedef struct arith arith;

extern arith *arith_new();

extern void arith_delete(arith *p);

extern int arith_add(arith *p, int x, int y);
extern int arith_sub(arith *p, int x, int y);
extern int arith_mult(arith *p, int x, int y);
extern int arith_div(arith *p, int x, int y);

#ifdef __cplusplus
}
#endif
// arith_capi.cc

#include "arith_capi.h"
#include "arith.h"

extern "C" {
  struct arith *arith_new() { return new arith(); }

  void arith_delete(arith *p) { delete p; }

  int arith_add(arith *p, int x, int y) { return p->add(x, y); }

  int arith_sub(arith *p, int x, int y) { return p->sub(x, y); }

  int arith_mult(arith *p, int x, int y) { return p->mult(x, y); }

  int arith_div(arith *p, int x, int y) { return p->div(x, y); }
}

In our C API, you’ll notice that we need to wrap our functions inside extern "C" to ensure that they’re compatible with C ABI. Also since extern "C" is a C++ keyword, we’ll wrap it in #ifdef __cplusplus directive to ensure that it gets only used if we happen to call this via C++. In the actual implementation side, you can notice that we use new and delete to do the memory management. The thing to note here is that using those keywords in “modern C++” is very much frowned upon since the language offers better ways to do that management with features like RAII, smart pointers etc., which basically makes it so that programmer don’t need memory management explicitly like we do here, but instead, they can let the compiler do it for you. We on the other need to use those keywords since we are similar management but from Haskell with its foreign pointers, which makes it so that we are able to leave the memory management to Haskell’s runtime and garbage collector.

Now we have the C++ bits done, we can proceed on how to interact with that via Haskell. All Haskell’s FFI features reside behind GHC’s {-# LANGUAGE ForeignFunctionInterface #-} language extension. So first, we need to include that in our Haskell files (either on top of the file or in the project’s Cabal file), and we can already import some of the needed modules.

{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Control.Exception ( mask_ )
import Foreign.Ptr ( FunPtr, Ptr )
import Foreign.C.Types ( CInt(..) )
import Foreign.ForeignPtr ( ForeignPtr, newForeignPtr, withForeignPtr )

What are we importing here?

After the importing shenanigans, we can proceed on to make foreign imports to our code so that we can actually call the C++ code we just wrote.

data Arith

foreign import ccall unsafe "arith_capi.h arith_new" c_arithNew :: IO (Ptr Arith)
foreign import ccall unsafe "arith_capi.h &arith_delete" c_arithDelete :: FunPtr (Ptr Arith -> IO ())
foreign import ccall unsafe "arith_capi.h arith_add" c_arithAdd :: Ptr Arith -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "arith_capi.h arith_sub" c_arithSub :: Ptr Arith -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "arith_capi.h arith_mult" c_arithMult :: Ptr Arith -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "arith_capi.h arith_div" c_arithDiv :: Ptr Arith -> CInt -> CInt -> IO CInt

So what’s happening here:

Finally, you’re actually able to call these functions.

-- | Create a new foreign object that will be cleaned after it's not in use
-- anymore. It also uses mask_ in case the pointer leaks if an exception happens.
newArith :: IO (ForeignPtr Arith)
newArith = mask_ c_arithNew >>= newForeignPtr c_arithDelete

main :: IO ()
main = newArith >>= \arith -> withForeignPtr arith $ \ptr -> do
  -- Foreign object is now unwrapped to a foreign pointer which you can use in
  -- any FFI function you described above.
  c_arithAdd ptr 1 1 >>= print
  c_arithSub ptr 1 1 >>= print
  c_arithMult ptr 2 2 >>= print
  c_arithDiv ptr 2 2 >>= print

Now you should be able to run your program and interact with C++ in safe manner from the comfortable world of Haskell.

$ cabal run
# ... cabal stuff ...
2
0
4
1

So you can see that while calling C++ from a foreign language is definitely possible, it just requires a bit more ceremony than calling C from these kinds of languages. I initially started to bang my head against the wall with these FFI shenanigans just for the need to use some C++ interfaces that didn’t offer C API, so hopefully, this proves to be beneficial to some. At least, I can use this to freshen my memory in the future since I can guarantee that I’ll forget about it.


The Poetry of Programming

Posted on 8th of December 2022 | 113 words

I found this great quote from Richard P. Gabriel , Lisp hacker and a poet, which summarizes nicely my feelings towards programming and how I see it as a creative field more so than technical:

“Writing code certainly feels very similar to writing poetry. When I’m writing poetry, it feels like the center of my thinking is in a particular place, and when I’m writing code the center of my thinking feels in the same kind of place. It’s the same kind of concentration. So, I’m thinking up possibilities, I’m thinking about, well, so how do I reinvent the code, gee, you know, what’s the simplest way to do this.”

  • Richard P. Gabriel

Blogging as a Form of Free Writing

Posted on 7th of December 2022 | 520 words

My blogging, or at least the topics and themes of it, has always been quite volatile, to say the least. I haven’t really ever given too much thought to it. Still, I’ve always just written about topics that interest me at the moment in question. This might be the big reason behind the fact of why the topics in this blog vary pretty heavily, all the way from geeky programming topics, to spirituality, to ranting about corporations. You could describe this kind of writing as some sort of “free writing”, a commonly used technique in creative writing.

Regarding my own creative writing, it has always been mainly in Finnish, but these blatherings that I’ve collected for this blog have been fully English. Like my blogging, I’ve never really given too much thought to my language choice here. Maybe there is a small egomaniac in me, like in every other “artist”, and I initially thought that perhaps someone really outside Finland wants to read my writings here, which is why I chose English. Who knows?

But what is this commonly used technique called “free writing”? What does it involve? Well, like the name suggests… it involves free writing. Usually time-boxed writing and usually quite raw and often unusable material. The good thing about this sort of writing is the possibility of just focusing on producing text alone without the fear of censure and with little concern for conventions and mechanics. No regard for spelling, grammar or other corrections. Free to stray off-topic and let your thoughts lead the way. Although considering this blog, my posts haven’t been this free.

Writers of any kind, prose, lyrics, or poems, often tend to be proponents for this sort of writing where you don’t need to worry about failure, deadlines or other forms of resistance. Often mentioned how it helps to “unblock” your writer’s block. Being especially beneficial when done regularly. Is there data on that? Probably. I just don’t have it. I just know how it affects me, whether it is writing incoherent blogs for my website, writing interesting, or in my case not so interesting, lyrics, or any other kind. Just writing something tends to be the biggest helper when it comes to writing anything. Shocker, I know.

Overall, when it comes to writing, it is a skill like any other, and it needs honing. You might be currently writing your next big novel. However, you can still benefit from writing without any framework, a plan, no knowing where it’ll go, no apathy, no resentment, just words on paper. Just for a short period. Maybe 15 minutes. Maybe 30 minutes. Maybe as long as you can’t think of anything, like writing in a trance. This sort of writing doesn’t focus on the product itself but more on the thought process relating to writing.

After that, try returning to your project, whatever it might be. Maybe opening and limbering this process in your mind before you start “real work” helps you. Perhaps it can direct you to places that you never thought to explore. Some might hate free writing, and some might love it.


In Praise of Public Domain Literature

Posted on 1st of December 2022 | 382 words

I’ve been living in Berlin for under a year, which has made a small dent in my reading habits. Not necessarily anything terrible but something I haven’t been used to before. When I’m reading books here, those tend to be written in English or German, to a smaller extent, while I’m learning the language. But my native language, Finnish, is forgotten on that list. I have always read books regularly in English, but at the same time, I’ve also read those in Finnish. But now, when I’m living abroad, the availability of those books is quite limited. Especially because I mainly read in eBook format due to the practicality of those. I had loads of books when I was still living in Finland, but moving with the number of books I had was painful, to say the least. This was the biggest reason I started reading more and more eBooks. Unfortunately, it also happens that the eBook industry in Finland is not as “booming” as it is abroad, which means that most of the new books written in Finnish don’t make it to that format. So when it comes to new books, I’m pretty out of luck.

But I still want to read in Finnish, so how can I fix this? Sure with some tremendous luck, I might find a shop here in Berlin that sells Finnish books, but that is not a guarantee. Then I realized. I’ve been a big fan of Project Gutenberg , a volunteer effort to digitalize and archive many cultural works around the world focusing on works that have become public domain due to their age or other reasons. While I had been familiar with the project earlier, I had always mainly used it for English literature and works. It wasn’t until recently that I realized they also had a vast library of books in many other languages, including Finnish. Everything is published in plain text and when available in various eBook formats also.

So I wanted to make this small post of appreciation for this project and how they helped me in many ways to continue reading great works of literature in my own native language when those are not so readily available. If you’re willing, please support their project by donating or spreading the word.


Reading List

Posted on 13th of November 2022 | 239 words

For years, I’ve been a relatively voracious reader, but for one reason or another, I’ve never really given too much thought to my reading. Sure, while I was in school, I did the occasional book report. Although considering my history at school, these probably weren’t given much thought. This has meant that I mainly just read what I enjoy, put the book away, and that’s it. Although, occasionally, on good books, I might’ve returned to them more than once.

Lately, I’ve wanted to start to change this habit, and I’ve decided to do this is to begin maintaining a reading list/queue and writing some brief notes after I’ve read the book. By these notes, I’m not talking about any summary of the topic or anything like that but more so as a way of saving thoughts and ideas about what I’ve read. Of course, this probably also means that not all books I read are worth taking notes, but at least those that I find fascinating/interesting/great will probably have these.

Since I’ve been reading about one book per week for many years, naturally, I can’t remember everything I’ve read. This is why I will probably just reread many of the books I have already read just to include those on my list. Thankfully, I only read good books, so this won’t be a chore… right? I’ve also decided to maintain this reading list online, which can be found here.