May 3, 2008
I recently decided to rethink and reimplement AutoForms. This post will be the first of a series that explains the hows and whys of this reimplementation.
Why AutoForms need a replacement
AutoForms started simply as a library to generically construct GUI forms, such as a settings dialog. But as development has progressed more and more features has been been added. It has gotten to the point where AutoForms tries to be a complete GUI library on top of WxHaskell, in stead of just a library to generically construct widgets in cooperation with WxHaskell.
The feature creep has let to several problems:
- Less separation of concerns than possible
- Too much to maintain and develop
- For potential users of a AutoForms I am asking a lot, as they will have to understand a hole new and complex library.
- By exploring many different features, non have really been explored to a satisfactory level. AutoForms has become Jack of all trades, master of none.
I have dealt with these issues in two ways. Firstly I have created an interface to AutoForms (called AFWx) which is very simple for a person that already knows WxHaskell. Secondly to better separate concerns, I have been factoring out the different parts into independent modules.
While these remedies have helped, it was not enough. I wanted a library that focused on generically constructing Widgets from data types. As such, large parts of the code in AutoForms were unneeded. And large parts needed to be changed. Therefore starting from scratch seemed attractive. While I was not sure it was the best choice it did seem like an experiment worth performing. And in retrospect I think it turned out really well.
Another issue that led me to reimplementation were composability. Just like most data types are composed of other data types, a library like AutoForms needs to compose widgets to bigger widgets. Unfortunately WxHaskell lacks in composability. Thus AutoForms contains the WxM monad to compose widgets. The interface of the WxM monad is considerably different from ordinary WxHaskell code and those places a burden on the user. But as I recently discovered it is possible to achieve composability, while still keeping the WxHaskell look and feel. This makes a strong argument for scraping the WxM monad. And as the WxM Monad is a central piece of AutoForms, it also makes a strong argument for reimplementing AutoForms.
The reimplementation resulted in not one, but two new libraries. The first library is called WxGeneric and constructs widgets generically. In contrast to AutoForms, it do not try to reinvent the GUI library. While it does make GUI creation easier, most of the GUI application code will still look like ordinary WxHaskell code. Indeed most of the GUI application code will call WxHaskell directly.
When constructing AutoForms, I discovered that some of the hardest to implement code was not specific to any one GUI toolkit. It therefore seemed natural to abstract this code into a separate library. This library is called SybWidget and WxGeneric builds upon it. However, as it is very difficult to make a generalization from just one example, I also refactored AutoForms to use SybWidget. The refactoring indeed resulted in changes to SybWidget that made it more generally useful. It is my hope that GUI toolkits similar to WxHaskell (like Gtk2Hs) will find SybWidget useful and implement there own generic widget libraries.
Separating the WxHaskell specific parts from the rest, allowed me to make a library that do not use the IO monad. This makes it possible to test SybWidget with QuickCheck. For some functions the important aspect to test was not so much varying values, but varying types. Here QuickCheck approach do not make much sense and I opted for HUnit instead. I use Haskell Program Coverage for measuring SybWidget’s test coverage.
Future of AutoForms
The simplicity of WxGeneric (as compared to AutoForms) is very attractive, but it is not without cost either. For example AutoForms tries to be “intelligent” about the automatic layout of widgets. This “intelligence” will be lost when using WxGeneric. Also AutoForms has better static type safety than both WxGeneric and WxHaskell. In the future I might try to develop these ideas further. Either as part of AutoForms or in a separate library. But I do not think that these features should be included in WxGeneric. It should be as it is, a simple library to generically construct widgets.