Not everything that can be counted counts, and not everything that counts can be counted.
― Albert Einstein
Software Development and Data Consultant
Not everything that can be counted counts, and not everything that counts can be counted.
― Albert Einstein
As I am in the process of developing an application for data analysis on chemical data the need for building a desktop GUI came up. Why desktop you ask? Excellent question! I think for this particular project, the combination of ease of use, data privacy and performance make it worth exploring an approach with a local, self-contained application instead of anything involving remote servers.
Actually in the end we might build a SaaS too or move to such a model completely.
Nevertheless I am exploring the desktop GUI application space now and wanted to see how one could do that in Clojure in beginning of 2017.
The most promising candidates are JavaFX and Electron (based on Chromium, NodeJS, HTML5). I ruled out Swing even though I got only positive feedback about it from the few people who used it in anger (Seesaw would be the Clojure lib of choice). Swing is getting old and has found its official successor in JavaFX. That being said, there are also people who already claimed JavaFX dead… which would leave us without any GUI framework alive in the Java world!?
JavaFX is Oracle’s take on a framework for rich client applications and it is included in the official JDK and JRE bundles since Java 7. As it is included in those bundles it is readily available in many cases without even having to pull in additional dependencies. Being a Java library it can be accessed via interop from Clojure conveniently. When growing the application once might want to create some wrapper functions and macros to map it more nicely to Clojure idioms.
There are also a couple of wrapper libraries available but it seems like most of them are not actively maintained and a rather early versions or even prototypes. There is one library that is quite new and tries to map the React model to JavaFX: Having a declarative UI tree spec which gets rendered from a single source of truth state and uses efficient diffing to find out what actually needs to be rendered. That library is halgari/fn-fx developed by Timothy Baldridge. As I really like that rendering model for being close to the functional programming paradigm while still being very practical and pragmatic, I wanted to give this a try too. Especially as the declarative UI building would be very close to how I would approach it on the web. Which brings us to Electron…
Electron bundles Chromium with NodeJS and provides a framework to build desktop applications with HTML5 technologies. Electron became very popular quickly and has been adopted by some high profile projects including Slack and Microsoft Visual Studio Code. The cross platform support seems to be really good and it comes with nice features like automatic updates and crash reporting. As it is based on web technologies it is indeed very easy and natural for web developers to build applications with it and it supports most things that you would use for building websites too including React. All of that sounded very good to me! Even though I am not a huge fan of HTML, CSS and JS I knew I would be able to be fast with those technologies.
One major downside with that approach for me though: You would be living in a JS runtime (actually two: Chromium & NodeJS) and had to use Clojurescript where I would really prefer using just Clojure. First I would like to leverage some Clojure and JVM libs that are not available for Clojurescript and secondly I always had rather mixed experience with the Clojurescript REPL development. When things were going well it worked half-decently but often it was just broken and a PITA to get it to work again.
Of course with Electron you can call out to any remote or local server or even start local processes via the included NodeJS backend. This way you could for example communicate with another Clojure program. One approach to integrate a Python backend is described here. However this seems a bit too much for me when I could just go with a single Clojure application instead.
The support for desktop GUIs with Clojure does not look that great IMHO. I would think that is most likely because not many people are working on such GUIs. As a JVM-native approach JavaFX still seems to be the best bet. If one can live with the JS runtime then Electron would be an excellent choice.
For the data analysis application I am currently working on, I will most likely go with JavaFX. Either via simple interop and some wrappers or using halgari/fn-fx because I want to have access to the JVM and a good REPL experience. I am however evaluating Electron too and you can find some spike implementations I did with those technologies over here on GitHub. As I am writing this those are still work in progress with the fn-fx-ui being the most complete.
I plan on finishing the spikes in the repo and blog about the experience and its outcomes.
[…] stated in a previous post I am in the process of building a GUI application and I would like to use Clojure for that. In this […]
Timothy Baldridge says
January 20, 2017 at 12:51Let me know if you hit any major issues with fn-fx. I’ve written several small examples, but have yet to try to develop a huge app with it yet, so I’m sure there’s a few rough edges.
Nils Blum-Oeste says
January 20, 2017 at 16:13Thanks! I actually hit a few things, most can be found over here on the github README: https://github.com/nblumoe/clj-ui-spikes/tree/master/fn-fx-ui
I also had to do some work on fn-fx. Not yet ready for a PR (missing some tests and maybe refactoring) but I am working on it: https://github.com/nblumoe/fn-fx/tree/implement-collection-diff-updates
Rockiger says
January 20, 2017 at 18:29While probably not that popular I use hy-lang with PyQt.
Disadvantage: no Clojure data structures
Advantage: by far the best GUI framework and having lispy/clojure-like syntax
Piotr says
May 23, 2019 at 13:42For people working on data science/machine learning, Python is much more reasonable choice than Java. Then, it is much easier to use Hy than Clojure. I use Python and PyQt5, but I want to exploit a lisp. Your post showed me a very nice alternative, thank you!
Michael Schwager says
September 14, 2017 at 19:19Hi, I too am writing a GUI using Clojure and JavaFX. The tool will eventually be a (yet another) schematic capture/layout tool for elecrtical engineering hobby purposes. I have created a bunch of macros and stuff, similar to yours (sort of) which makes JavaFX pretty easy and fun to use in Clojure, with much less boilerplate than what I’ve seen in Java. Coupled with getting stuff running in the repl, it makes working in other environments feel kind of stifled.
Jeff Friesen says
February 21, 2018 at 16:23I have not tried this lib but it has a JVM backend and an Electron front end: https://github.com/jreznot/electron-java-app
Nils Blum-Oeste says
February 28, 2018 at 12:35Nice, thanks for sharing!