“Executive” Summary
This post is more of an op-ed piece than anything technically illuminating, and certainly not Haskell specific. Those not wishing to be exposed to a high level of pontification may prefer to pass. Similarly, those unused to my writing style may be disconcerted at just how many digressions I manage to fit into a short blog post. Imagine something like Steve Yegge, but without the wit, expertise or insight, and you shouldn’t be too far off. Again, please pass if this is an issue for you.
If you are a time-starved executive type who needs to cut to the content and ignore the crap, see immediately below.
tl;dr: We built something which might be of interest to others. Should we bother to make it accessible to others when it would make our own lives, and those of our existing community, harder?
wxHaskell – why bother?
I am the lead maintainer of wxHaskell, a Haskell binding for the wxWidgets library. As part of a coming push to make wxHaskell compatible with wxWidgets 2.9, we have done quite a bit of work which has raised questions as to the ‘best’ way forward in a number of areas.
As Open Source communities go, the Haskell community is probably a relative outlier in a number of ways which matter to an Open Source Haskell contributor:
- It is relatively small;
- Its members have an astonishingly wide range of abilities and interests;
- It is incredibly good natured and helpful to all, pretty much regardless of level of ability.
The small size of the community means that many projects struggle to maintain a significant level of engagement over time. There are, I think, relatively few people interested in the nuts and bolts of maintaining a GUI binding, and this effort is split across several GUI bindings (Gtk2Hs and wxHaskell being probably the best supported, but with QTHaskell and HOC). There are good reasons for the split opinion on which GUI library to bind with, and I won’t explore them here.
Why not Gtk?
One aspect of wxHaskell which I hugely appreciate is that it works on the three main platforms: Linux and other unices; Windows and OS X, and delivers ‘native’ application look and feel without too much problem on all, and this is an attribute I’m determined we should keep.
In common with many programming languages, Haskell has an FFI binding which has no problem interfacing with libraries written in C, but cannot natively interface with libraries written in C++. There are very good reasons for this (basically that there is no way for anything other than the C++ compiler which originally compiled a C++ library to know how to call or link to the functions in that library – or more technically, every C++ compiler does name mangling differently).
This is probably the reason that GTK has become the default GUI binding for many non-mainstream languages. GTK may have <opinion-not-fact>a rather ugly approach to object-orientation</opinion-not-fact>, but all of its APIs are accessible in standard C, and it is therefore relatively straightforward to write a low-level GTK binding.
GTK is an outlier in the GUI world, however. Most GUI libraries are designed in object oriented fashion, using languages, like C++, which natively support object orientation. There are also good reasons for this: GUIs are <opinion-again> one of the few application areas </opinion-again> where classical object orientation is a very good way of expressing design (the other is designing libraries for classifying shapes, which seems to be a staple of OO tutorials, but not something for which I have seen an overwhelming demand in my professional life).
Wrapping C++ for beginners
Fortunately, it is very simple to make C++ code comprehensible to systems which only understand C. Suppose you have a class something like (borrowed from C++ Language Tutorial):
class CRectangle { int x, y; public: void set_values(int, int); int get_area() const; };
It is straightforward to write a wrapper for the class, callable in C, which looks (if you ignore error checking etc.) something like:
extern "C" { void CRectangle_set_values(CRectangle* self, int x, int y) { self->set_values(x, y); } int CRectangle_get_area(CRectangle* self) { return self->get_area(); } }
You will notice that in each case, we pass around a pointer to the C++ object and use it to call the C++ function from within a function declared (with the “C” modifier) as being compatible with C calling and linker conventions.
Most of wxHaskell is wrapper code of this type. It’s not hard to write, but there is enough of it required that the writing soon becomes tedious and error prone. SWIG is designed to do this sort of thing, but it doesn’t have a Haskell backend, and when I started to work on one I quickly discovered that the documentation is a long way out of sync with SWIG itself, although the SWIG community is very helpful on the mailing lists. I may come back to a SWIG backend one day, but life is short!
That was a pretty long digression which was aimed at saying the what we have actually built is a C binding to wxWidgets. This is therefore just as accessible to most language FFIs out there as GTK, and would form a pretty good basis for a wxWidgets binding for many non-mainstream languages.
Standing on the shoulders of giants (and the not-so-giant)
Now, all of this good stuff is built on a wide range of Open Source code. Obviously the most important component is wxWidgets itself, but wxHaskell itself was forked from wxEiffel. We also use wx-config-win, a replacement for wx-config on Windows machines, and a project called wxC was forked some time back from wxEiffel (I think) to make a generic C wrapper.
In common with many Open Source projects, unfortunately many of these are moribund – the original contributors moved on and were never replaced, and so we end up with a fork or replace question. In most cases the answer to this is easy: fork – replace is almost always too costly. However Haskell is very productive indeed, which puts the question more finely in balance, and leads me (barring a few more digressions) to what I am really pondering.
How can I best serve ‘the community’ and what is that community anyway?
As I mentioned, right now we have a fairly complete C wrapper for wxWidgets. It builds as a DLL/shared library, and uses plain C headers, which means it could be used by pretty much any language.
There’s a barrier though. In order to make it as easy as possible for the Haskell community to set up and use wxHaskell, we have used a very Haskell-centric approach to building the library (Cabal, which is the standard way of distributing Haskell source libraries).
Unfortunately, I’m sure this would be a disincentive to anyone from, say, the Ocaml, Forth, Lisp or pretty much any other language community from using or contributing to the C wrapper (“waddya mean I need to download 200MB of Haskell Platform just to build a C library?”). I certainly know that I get discouraged when looking at a potentially interesting project only to discover that I need to locate 15 different packages before I even get to try to build it – an operation which is far from guaranteed to be successful with many projects.
So now I, or rather the wxHaskell community, recognise that we have a conflict of interest: we have built something which might be useful to many other groups (but we’re not sure if there is anyone out there who cares), but making life easier for those other groups will make life harder for our existing community, at least in the short term.
However, the other side of the calculation is that if other language communities get involved in contributing to the C binding, we get a larger community with a greater level of contrbution and engagement.
So we finally come to the point: is anyone out there interested in a C binding to wxWidgets, and if so, are they interested enough to want to help?