Ideas for Clojure GUI libraries

15.12.2014 Permalink

Earlier this year I published a prototype to combine JavaFX with core.async to overcome some problems that I never solved in plain Java. Very recently, I sensed some interest in that prototype so I write a public post about my thoughts.

At the moment I have no plans to evolve async-ui as-is into a library, because it deals with numerous problems at once, i.e. it is not simple, and creating a GUI framework typically involves a huge amount of work. As it is today it just demonstrates that the idea of splitting UI code up into the following two conceptual functions

  1. build and update GUI from view state
  2. purely transform view state event by event
is an interesting approach for functional GUI programming, and that it can be combined with CSP style processes connected via channels to avoid nested callbacks, which - by the way - results in a crystal clear separation between GUI API access code and business related presentation logic.

It is the basis of a talk I give in January at ClojureD conf and it will remain a prototype. If, however, it turns out that many people actually want to have a more functional-style GUI programming experience in Clojure I would be willing to team up with others and put some effort in.

My ideas for such an endeavour are as follows:

1) I would rather focus on JavaFX than Swing, because JavaFX has a cleaner API, and Swing support has ended.

2) I would not like to create a "batteries-included" framework, because this would include numerous assumptions and trade-offs that might not fit actual needs and it's usually no fun to bend a framework into directions that its authors didn't anticipate in the first place.

3) One interesting aspect IMO is the transformation of Clojure data into the JavaFX scene graph. This is kind of the JavaFX version of React in browser DOM world. In async-ui this is currently done by the build multimethod that creates and configures controls, and by calling the setter functions to update data in controls. This transformation should be extensible in the sense that developers must be able to add transformation code for any individual control without touching existing namespaces (open-closed principle).

At the moment, with respect to this extensible transformation async-ui has two shortcomings: 1) the specification language in forml namespace is not extensible, 2) interactive development works, but rebuilds a Frame/Stage from scratch, so I would like to see a smoother way of merging changes into the scene graph.

It would take some exploration to identify the piece of non-trivial, reusable transformation related code that can be put into a library. At least such a library might provide some infrastructure and guidance. On top of this infrastructure, a benefit for real-world projects would be default transformations for widely used FX controls.

4) Application state management is a different aspect. Async-ui currently uses local state per Frame/Stage, not global state as in Om. I would like to keep the decision of how state is managed independent from the transformation problem. Cursors as in Om are IMO crucial for managing global state. A general cursor library would definitely be a useful asset. Sean Corfield started a ClojureScript cursor library for reagent which might act as a starting point.

5) Communication between GUI views, presentation logic and long-running code is another distinct aspect. My main requirements would be support for callback free code and a clear separation between GUI access code and presentation logic. I would like to keep the decision for the mechanism out of 3 and 4, but I'm not sure if this is possible.

In a concrete application I currently favor core.async over Rx-style libraries. I experimented with GUI and an Rx-like flatmap here. As you can see, Rx-style combinators help to generalize over different event sources and even treat the result of an asynchronously executed modal dialog just as another event source. But what I'm eventually after is a programming model that allows the programmer to stick to pure functions as much as possible. For this, I would try to get Rx or core.async to work more "in the background". With respect to GUI and asynchronity you get basically the same benefits from any of them, so I'd pick whatever is the more "mainstream" way in Clojure, which is core.async.

To sum it up, I think there a some useful pieces that one could build around Java GUI APIs to make them lend more towards functional programming. I hesitate to invest time here because I'm afraid that hardly anyone does Java GUI programming these days. If you think I'm wrong, drop me a mail or send me a tweet.