F# vs Clojure: new paradigms for old platforms

I decided that it was time to get into a new language. Being the unfocused, indecisive person that I am, I couldn’t decide between Clojure and F#, so I chose both. In a way, they are very similar. Both were made to interoperate with a mature, popular language inside of a VM while using an entirely different programming paradigm from its host language.

Clojure brought Lisp to the Java Virtual Machine, along with built-in Java interop. The promise of Clojure is that you get to write Lisp while reusing all the Java libraries and your existing Java code. F# has similar selling points: you get to write an OCaml-like language while at the same time reusing any C#/.NET library or code. While Clojure is mostly community-developed, F# has corporate sponsorship from Microsoft.

Both languages combine the object-oriented nature of their host platforms with their own approaches. F# is very functional in nature: you get immutable variables and data structures, first-class functions, lambdas, closures, currying, and partial function application. On the CLR, you can eliminate tail calls for recursion. The object oriented aspects are all present in F#, but they are treated differently than the ML-flavored features. You can declare a class in F#, but you can also create discriminated unions for pattern matching.

On the other hand, Clojure is a Lisp, so you can implement functional programming with a library, but it’s safe to say that Clojure is not functional in nature. Proponents of the language claim it’s functional (I believe several books mentioned this), but the power of Clojure is that it’s a Lisp with homoiconicity and syntactic macros. Clojure does have first-class functions and immutable variables and data structures. Neither F# or Clojure has the idea of pure functions (side-effect free functions).

To learn these languages, I did a lot of reading. When I was sick of reading and wanted to program, I decided to implement something simple: a CSV parser. There’s no standard for CSV (although there is an RFC), so I just chose/made up a definition that would fit most of the use-cases I’ve encountered.

A third language, for comparison

This may sound weird, but I decided to compare writing Clojure and F# against the exact opposite of these languages: C. It’s a language that is imperative, mature, has manual memory management along with pointers, doesn’t have strings, and doesn’t have a standard collections library. I realized that even with a small task like a CSV-parser, I was completely lost in how to organize my program and how to write clear, bug-free code. The program I wrote is terrible, but I’ve put it on GitHub regardless (the name is c-csv). The idea behind comparing F# and Clojure to C is that the former languages are very high-level with an emphasis on programmer productivity at the expense of CPU cycles and RAM whereas C makes the opposite tradeoffs.

It took me 7-8 hours as well as several pages of code to implement the parser in C. I love the terseness of the language, as well as the feeling of power when you create nearly all your tools from scratch, but I also disliked the fact I really didn’t have a choice.

F#

F# brought some big guns to the language shootout: type safety along with type inference, pattern matching, and discriminated unions. It has tons of other features that I’d use if I were programming something larger, but for a simple parser, I only needed a few basic tools. Incredibly, I wrote a parser in less than 40 lines and in less than an hour. It’s available on GitHub: I called it fs-csv.  I’m sure better programmers than I could outdo these stats, but I was blown away by the fact that even I could create a readable, incredibly short program that it fit easily on the screen.

Clojure

I tried the same with Clojure, but I realized that I didn’t understand the language. I ran out of patience with trying to build a CSV parser, so I instead spent my time on Clojure Koans and 99 Lisp Problems. That was a worthwhile experience, but I still don’t feel as though I really know Clojure/Lisp. Lisp is a powerful tool: you can use it to create your own language that then solves your application’s problem, or at least that’s the idea. I realize this, yet I’m not to the point where I think in Lisp. Within a few hours, I could think in F# (partially because I’d used Haskell and partially because it’s just a sensical language). I’ve worked my way through the Little Schemers book, but I’m still not a Lisper.

Another part that I just don’t like with Clojure is that it’s not typed and it doesn’t compile fully at run time. You create an application that will then compile your Clojure code when you run it. It’s the speed of compiling combined with the safety of interpretation. The stack traces are bit confusing as well (since you’re calling into JVM-land which is not built as a Lisp-machine).

Higher level languages are vastly more productive

My end conclusions were several. First, high-level languages like F#, Python, C#, or Java 8 are definitely time savers. A language with managed memory, built-in strings, collections, and first-class functions is always going to beat out C when it comes to developer productivity. Given how little code you can use when building things in F# compared to C, you also win out for long-term productivity. It’s silly to think that once you build all your tools in C you can create your own high-level language and be just as productive as in C#. A modern, managed language with batteries-included core libraries will beat the pants of off C. This should be obvious, but this exercise made it painfully clear.

Second, F# is a great language that has tons of time-saving features. I really like C# (in comparison to Java), but I want type inference along with the functional aspects of Haskell. Speaking of that language, I do not miss having to think about having purity by default, or the issues with Cabal, or the lack of libraries. F# has access to all .NET libraries. Oh, and it’s easy to compile JVM code to .NET, so you get all JVM code too. No, seriously. I used the Java Stanford NLP library in a little Java project because I wanted to fiddle with it. I recently discovered that the Stanford team compiles the code to .NET as well since it’s really simple to do so with a tool called IKVM.NET. And they put their code on Nuget, the package manager for .NET. Let me say that again: the Stanford team produced a Java library that’s really awesome and .NET developers can use the same library without the Stanford team rewriting it in C# or F#. It’s like an infomercial: order F# now and you’ll get all the Java libraries thrown in too!

Third, Lisp is hard for me, and I assume it’s hard for a lot of programmers who come from a Java/Python/C# background. In these languages, you write a solution to your problem. In Lisp, you write code that will write a program that will solve your problem. This is the next step in how programming languages will work and it only makes sense. Every programmer, after typing up some program, will realize that they have written the same program or the same lines before. There’s a deep desire in all programmers to solve the problem once and never again. Constructs like functions, objects, generics, libraries, code-generation, lexical macros, and aspect-oriented programing are all means to further this end. While they approach the ultimate goal, you still have to write so much repetitious code. Lisp holds out the promise of programming your programs, of allowing you to create code that writes code for you.

Clojure is a Lisp, so it comes with the all positives and the negatives of that language. The core idea of Clojure is that you program your program instead of directly solving the problem. This added layer of abstraction comes with an incredible amount of power along with an additional toll on your brain. Learning to program is not easy, and programming a program is even harder. Lisp or a Lisp-like language might be the future of programming, but right now we have to build software teams with average programmers. Lisp is not the language of average programmers.

After using Clojure, I must report with a heavy heart that I don’t think there’s much hope that Java will be replaced. With Java 8 and the community libraries, you can get too much out of Java. Every project will probably use Guava, Apache Commons, and a hundred other libraries to patch the language deficiencies, but that’s better than the tradeoffs of all the other options.

In the end, I would love to use F# in a full-time job. I can’t say the same of Clojure, but I know that has more to do with me than the language itself. I can say that I would never use a Lisp if I wanted to hire people (unless I had a big budget in a big city). F#, on the other hand, would fit in well in a stodgy corporate setting as well as a nimble startup. I wouldn’t mind putting it into the hands of a junior programmer.

Tagged with: , ,
Posted in Programming
2 comments on “F# vs Clojure: new paradigms for old platforms
  1. Dev Danke says:

    I really appreciate you sharing your experience with these functional languages. I’ve always wanted to learn a functional language. Because I’m a Java programmer, my choice was between Scala and Clojure. Clojure seems more functional and less of a hybrid, so I chose it.

    I’ve been tinkering with Clojure on and off for a couple years. Yet I still don’t feel very comfortable or skilled with it. With the same amount of effort, I easily became proficient at Ruby, Python, and Dart. So I’m starting to wonder why Clojure is so hard to grok. I still don’t have an answer. But it is helpful to know that you felt it was harder to learn/use than F#. I’ll keep this in mind.

    The thing that keeps me going with Clojure, at least for now, is its connection to Lisp and Lisp’s long, storied history. I’m hoping the functional concepts I learn will be useful in processing Big Data.

  2. Tensor says:

    I’m just a beginner as far as java goes because I never liked the syntax but I worked as a full stack Python dev and a .Net programmer for about 10-15 years now. I tried f# and just hated it, then I tried elm and loved it but found it too constrictive, I went around and did this with like every functional language I could get my hands on, in particular I wanted to find a language to replace JavaScript because I hate it so much. I tried TypeScript and all of those functional superset languages to javascript and they just werent good enough. In comes clojure. I started learning clojure by my self about a year ago. Now the majority of my work is done in clojure/clojurescript. The language is just so productive and powerful for almost everything I’ve used it for and once you get past the lisp syntax and the rest of the language is very very small and compact and decently easy to pick up.

Leave a Reply

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

*