Something has recently occurred to me as I was considering the proposition (put forward by the Python programmers and, I think, correct) that a programming language is also a User Interface. There is a fairly good analogy between the state of programming languages today, and the state of the operating systems for personal computers circa 1986 or 1988. Ignore mainframes and workstations for the moment, and just focus on the PC world.
The functional programming languages- Haskell, Ocaml, F#, Scala, etc- are Unix. Very solid foundation, terrible user interface (anyone remember Motif? That’s what passed for a Unix UI in 1986, and much later). Widely talked about in the PC world, but (except for a few brave and crazy souls) effectively not used. Also, very popular with the academic crowd.
The OO Scripting languages- Ruby, Python, Groovy, etc.- are the Macintosh. A beautiful user experience, no doubt- but underneath the hood there is no there there. Also, very popular with the beret wearing crowd.
Java and C#, then, are Microsoft DOS, or maybe Windows 3.1- the structural underpinnings of the Macintosh, except not as good, with the user interface of Unix, except not as good. And with the user share to dwarf both into utter insignificance, due to wide spread business adoption. The choice of all who wear suits.
Flamewar: Activate!
Seriously, looking back at the unix vr.s mac debates from that era (that I participated in- on the Unix side, naturally), neither side really “lost”. What happened was not that we were forced into choosing an OS with good fundamentals and lousy UI, or lousy fundamentals with a good UI, it’s that the lousy UI OSs developed good UIs (KDE, Gnome, Windows 95/98), and the lousy fundamentals OSs developed good fundamentals (Mac adopting Unix, Microsoft adopting NT).
Let me develop this analogy further, to explain what I mean. Functional programming languages really focus on, and really excel at, the “core” of programs- those places where it’s the program talking to itself, where typed data structures, algorithms, functions, modules, and internal (written explicitly for this program) code dominate. Dynamic languages really focus on, and really excel at, the “edge” of programs- where the program is interacting with the outside world- the user, other programs, the file system, etc. Here, strings, processes, files, UIs, shared libraries, etc. dominate.
It is wrong to say that the “core” or “edge” of programs are more important- different programs are more “core” or more “edge”, but the truth is all programs are both “core” and “edge”. Just like it’s wrong to say that the UI or the kernel is more important for an OS- like of a good kernel lead to the Mac’s inability to walk and chew gum (aka multitask) at the same time, while the like of a good UI meant that people are still loathe to try Unix, even decades later.
Likewise, the lack of a good core means that doing large projects, or maintaining code, in languages like Ruby or Python, is very painful. On the other hand, doing any sort of process management or scripting in Ocaml is also painful. Note that getting the core right in a language is about as hard (although in a different way) as getting the edge right.
These different strengths show up in the different sorts of programs each group “prefers” to solve. Functional programmers tend to the sorts of programs that have a lot of “core” but very little “edge”- the classic example here is compilers. Meanwhile, dynamic languages tend towards programs that are lots of “edge” but very little “core”- web sites, scripting, that sort of thing.
It’s not shocking, today, to believe that you can do both in the OS- have a good UI and a good kernel. Mac people no longer feel the need to justify the lack of virtual memory protection, for example, so they no longer claim this is not needed. And Unix people no longer need to defend command line interfaces, and questioning the need for GUIs (or claiming that Motif is “good enough, if you really need to”). There is a difference between justifying or defending an unfortunate feature, and promoting a good feature.
The difference is the common, known-bad, ground- DOS in terms of OSs, Java/C# in terms of languages. Everyone used DOS, whether they wanted to or not- so the Unix people had experience with an OS that had a lousy kernel, and thus could compare the with (unix) vr.s the without (DOS). What they couldn’t do is compare the quality of UIs, as every OS they used had lousy UIs. Likewise, the Mac people could compare OSs with good UIs (mac) and bad UIs (dos), but all the OSs they use have lousy kernels, so they can’t really judge what a good kernel is worth.
If, as the OS analogy and common sense suggests, the answer is to do both well, more dialog is needed. But also a clarity in the dialog. Beware of phrases like “you don’t really need” or “you don’t care about”, negative phrases. You might not need, or care about, something here and now, but that may just be because you’ve never encountered the other side. Instead, focus on the “you really need” or “you care about”, positive phrases. At some point in the near future I need to finish that post I’ve been working on, on the things Ocaml did right, the things you do care about and do need (short list for the curious: strong static typing, purely functional data structures, modules and functors, great GC, native mode compilation). But at the moment I’m more interested in the other side- what are the things that Ruby, Python, Groovy, etc. do right?
The floor is open.
Related posts: