Alternatives to the JVM for Portable Desktop Applications

Published at 19:17 on 16 November 2025

I have been using the JVM (Java Virtual Machine) to host desktop applications I develop. Originally I wrote the code in Java, but in recent years have switched to Kotlin, because it is a more modern language with a more concise and expressive syntax and a more sensibly-designed standard library.

The big problem with Java is not the language, it is the culture around the language. I have a friend with a number of pet sayings, one of which is “tradition is mightier than innovation,” and that certainly applies in spades to Java. There’s just so much bad tradition enshrined as respected convention in the Java world. I call the result Java Community Antipatterns or JCA’s for short.

Kotlin is better in the JCA department, but due to its intellectual proximity to the Java world, some of the Java brain rot has inevitably bled over, so Kotlin still has its issues. To pick just two examples:

  • Its Ktor Client HTTP request library is a lot more complex than it ought to be (way more complex than the Requests library that is common in the Python world or the standard System.Net.Http package of the .NET world). Despite the complexity, some of its features, such as bearer token management, still manage to fall short of what is commonly needed.
  • Its lightweight multithreading is likewise (there are both Job and Deferred objects, both very similar yet subtly different, where .NET gets along just fine with a single Task object).

On top of that, for a lot of things, there simply isn’t a Kotlin library. You end up calling a Java library. That is easy enough to do, because Kotlin runs on the JVM and was designed to interoperate with Java code, but the Java library is inevitably a lot clunkier and harder to use than it ought to be, due to those JCA’s.

If it weren’t for the JCA’s, Kotlin would be a near-ideal programming language. If it weren’t for the heat and dryness, Phoenix would have a near-ideal climate. (And aside from that, Mrs. Lincoln, how did you enjoy the play?)

So I decided to kick the tires on potential alternatives yet again. Always a good idea, because the state of the art is always in flux in the computing world. And the answer I got was: despite the flaws of the JVM, it’s still hard to do better than it.

Mostly, it boils down to three things the Java world got right:

  • To prioritize platform agnosticism.
  • To include graphical user interface (GUI) capability in the core framework.
  • To prioritize, or at least facilitate, making the graphical elements in Java GUI programs harmonize with the overall pattern language of the platform the application happens to be executing on.

The first two encapsulate the “write once, run anywhere” philosophy that has been one of Java’s key design principles basically since Day One. Other virtual machines still just don’t do as good a job of actualizing this principle.

This most often manifests when graphical desktop applications are involved. Pretty much any virtual machine out there will do a great job of running command line utilities or daemons running as detached jobs portably.

Python, for example, has a great cross-platform GUI library called PyQt. Alas, it doesn’t ship with it; one must add it on. And, like many Python libraries, it isn’t written purely in Python. In fact, it’s mostly written in C++, a language that compiles down to machine code, not portable byte code. This makes it a lot harder to distribute a run-anywhere application, particularly on platforms like the Mac, which is unusually programmer-hostile in this regard.

Microsoft .NET has a very nice virtual machine, with a standard library that, unlike Java’s, is for the most part well-designed and easy to use. But it was written by Microsoft, whose corporate interests as the creator of Windows run counter to the ideal of platform agnosticism. .NET code can run (and long has been able to run) on Macs and Linux boxes… as long as you stick to command-line or daemon programs. Out-of-the-box desktop support is no longer strictly limited to Windows (Macs are now supported), but Linux is left out in the cold even as of this late date.

There are third-party frameworks like Avalonia that claim to address this deficiency, but by not being present out-of-the-box, they raise the same gotchas that PyQt does in Python. Plus most of them fail badly when it comes to harmonizing well with the overall pattern language of a platform.

What it all boils down to is that I could shift to some alternate platform, and this would make my life easier in some respects, but only at the cost of making it significantly harder in others, or inescapably compromising the quality of my applications. It is far from clear to me that there would be any overall net benefit. In fact, I rather suspect the opposite would be the case. I guess that’s good news in a sense, as it means I probably haven’t been wasting my time using a suboptimal platform.

The Java community’s faults may be legion, but Java set out to be a “write once, run anywhere” language, and its virtual machine has to this date succeeded at that goal better than any other such environment of which I am aware.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.