Java vs Clojure - Lets talk ceremony!

2009-09-07 07:29:34
So, maintaining the perspective of a businessman, lets talk ceremony. There are undoubtedly multiple definitions of 'ceremony in code', but i'll boil it down to this
All use of resources for the sole purpose of pleasing an unforgiving and inflexible compiler and/or ritual
For IT Directors, looking at resource waste in the code itself is a discipline scarcely applied but for the rest of us its worth giving some attention. If I have my car in the shop for a tune-up I want the mechanic to use the right tools and thereby bill me the least amount of man-hours. Similarly if I'm going to pay somebody to write code for me, I want them to be as efficient as possible, which generally means And by using the right tools I mean those where you get the most functionality for the least amount of code and to achieve that, I have need to do away with ceremony. Learning by example! Differences become apparent in comparisons, so lets stack Java ( a typical OO, statically typed, curly braces language ) against Clojure ( a functional Lisp-1 geared for concurrency ). The task: I want to define a list of an arbitary amount of elements. Parse this list and only return those element which are distinctive, ie. remove duplicates. First I'll show you some Java code which gets the job done, talk about it, then compare. [caption id="attachment_29" align="aligncenter" width="430" caption="code-snippit"]code-snippit[/caption] People reading this code who are not carrying with them a great deal of sympathy for ceremonial waste of their money will probably have the following questions: Q: Why do I need all the imports? A: Java has lots of dependencies which are all present in the standard Java installation. This is a clever way to structure the code. Q: Okay, but why do I need to write 'import' on every line... That seems redundant! A: Thats ceremony. Q: Why do I need a class for this? A: Because classes are the only place you can puts methods, and methods is the only place you can put code. Q: Why do I need to specifically tell Java that my elements are of type <String>? A: Because Java is statically typed, so its not willing to work out the obvious, a string is a string. Basically you're paying me to do the compilers job. When you run this Java program, dlist will contain "foo" "bar" "baz" when exiting. Thats the result we were going for. Lets try to write a Clojure program which does the very same thing. For newcomers: Dont be distracted by the "user>" prefix on every line, thats how Clojures REPL tell me which namespace I'm in. Since Clojure development is very interactive I just write my code, hit enter and it compiles and runs. [caption id="attachment_29" align="aligncenter" width="350" caption="code-snippit"]code-snippit[/caption] So, we went from 28 lines down to 1. And before I get into the details ask yourself this question: When bug-hunting, which version is easier to reason about? In Clojure I can have classes, but I dont have to. I can define object of any type, but only when I need to. I can of course have code, but I dont need to stick it in methods. Since Clojure is a functional language, I have all my sequence techniques (like distinct) right in the core. Now the critics might say: "This is a set up. You picked an example for which you knew Clojure had a function" and thats right, I did. But not wanting to win by means of cheating, I've also written a Clojure version which mimics the Java version: [caption id="attachment_31" align="aligncenter" width="438" caption="code-snippit"]code-snippit[/caption] Down from 28 to 9 lines. I still have my imports (though I didnt need them), but Clojure doesnt want me to write neither 'import' nor 'java.util.' more than once. I define my list 'lst' using 'let' and I can stick as many items in there, and of any type, that I want. If I wanted to add a element with the value "quux" this is the code I needed to write: Java: list.add("quux"); Clojure: "quux"; If I wanted to add the an integer of the value 5 I would need to restructure my entire Java program, in Clojure I'd write: 5. But like you might have guessed from the 'distinct' example, loops are often not the best way to go and a more idiomatic example would be: [caption id="attachment_44" align="aligncenter" width="396" caption="code-snippit"]code-snippit[/caption] Some might "Sure thats actually only 4 lines of code, but they're difficult to write!" and thats exactly right. But isn't that what you want to be paying your hard earned money for? Competent code writers who have the skills to write quality code? As a buyer of a service my concern is not on the amount of training the consultant had to go through, but that the quality that I get out - I want my dollars worth! Can a shorter version of the java code be produced? Yes it can, I think by altering the imports to * (which has a different effect) and using list comprehension instead of an iterator you can trim some 10 lines of it. But thats beside the point. If you want you can do functional programming in QBasic, but at the end of the day its the things which your tools default to, that will dominate your approach. Conclusions: I appreciate being comfortable in a language as much as anybody, but once we start mixing development with money we need to make good decisions. I've witnessed a lot of language wars which quickly turn into emotional rants. Nobody benefits from this. Examine your own tools. How much money, time and resources are you giving to ceremony? How much are you and your clients paying for the comfort of 'what we always did' ? /Lau
bqlr
2009-09-08 09:16:31
many code lines means clear expression, if your wife or son only say several words in one day, do you know what they mean?
bestinclass
2009-09-08 10:55:14
@bqlr: You hit on a good point which I have considered for an upcoming blogpost. Concise code must always be weighed against clearness. I think this is where a lot of 'golfers' forget to balance the scales. In this example however, I would say that the short code is much more clear and readable than the more lengthy one. If what you say could be applied in a general sense, then C would be a very clear language, yet we all know that even 10+ year old C programs still have new bugs surfacing!
Casper
2009-09-08 12:29:40
On the other hand, just using many words does not automatically mean clarity of intent. Software engineering has always been about finding common patterns and practices and factoring them into idioms. If we did not, we would still be writing our programs with goto statements and roll our own vtables, there would be no need for loops, polymorphism, exceptions etc.

And btw. for what its worth, my wife can talk all day without me having any idea what she means, but I acknowledge because I don't want to piss her off - much as the Java compiler.
bestinclass
2009-09-08 14:49:17
I've received a few comments from Java programmers looking to defend the faith by sending me more concise examples than the one I posted. I decided to give all these good people a joint response:

The point of this article was not to provide the most concise Java example/the most concise Clojure example. I stated this just above the conclusion. By inverting the example you don't invert the conclusion ( and nobody could provide a cermonial-free Java example ). I'm not saying that Java should be entirely scrapped, but I did say: Examine your own tools. Java has its place and you don't make business decisions based on a few examples like this, there's a multitude of factors to consider, but more on this in the following posts.

Thank you all for your feedback!
hohonuuli
2009-09-08 15:15:46
There's no argument from me that Java is more verbose than it needs to be. On the other hand, there are very few people who can look at your Clojure examples and easily discern what the code is doing. Readability of code is extremely important. Clojure and Scala are amazing additions to a programmers toolkit, but the code often strikes me as 'perl-ish' in it's ability to hide the intent. That's not necessarily a knock against the language as most savvy programmers will be careful to write code with obvious intent (i.e. that they can still understand when they need to modify it 3 years down the road. )
Harleqin
2009-09-29 16:07:27
@hohonuuli, regarding "there are very few people who can look at your Clojure examples and easily discern what the code is doing."

"I am now hitting the keys of my keyboard in an order that causes my browser to send a specific message to this website."

"I am now posting to this website."

While the second version is completely inscrutable to someone who doesn't know the meaning of the word "posting", it is much clearer than the first version to someone who does know that word.
Conciseness is an important part of readability.
penny
2009-09-29 17:02:32
I have become so frustrated with JAVA that i don't touch it anymore outside of  my employer building. My new little baby is definitely gonna be clojure...I started playing with it and i loved it; it s clear, concise, beautiful...It made me shake my head like "Why in the world did i have to learn OOP and Java in the first place?????" Anyway, i will have to thank java for landing me my first and also my current job.
antek
2009-10-02 13:57:37
Java is not about writing small code, there are other languages for that - (J)Ruby, for example. So why compare the code size?

But anyway:

Point 1. ArrayList - why use wrong tool for wrong job? Let's use Set:

1 import java.util.*;
2 
3 public class Main {
4     public static void main(String[] args) {
5         Set dlist = new HashSet();
6         for(String s: new String[] { "foo", "bar", "baz", "foo" })
7             dlist.add(s);
8     }
9 }

Point 2. It's valid not to parametrize Set; but when you do, you'll get more security when coding, and the compiler can defend you from *your* mistakes. I mean, that's the point of compilers, right? If we'd always made everything perfect, we'd use hexeditor and write x86 opcodes directly (or there wouldn't be x86 at all :)).

Point 3. Editor. The IDE is filling automatically some "ceremonial" lines. This puts me in a position that I only need to insert 3 lines of Java code instead of 9, or 5; that will produce a valid program, and it will be readable by far more programmers than the Clojure version (hint: teamwork, code reuse).

Of course I am aware that when taking this case more generally, the third point may sound like a bold exaggeration, but it still sticks with the message of your post: know your tools. I also agree that Java has a lot of things which are not essential for programming, but it also has a lot of additions which can remove some of them, f.e. http://projectlombok.org . If your tool offers aids like templates, annotation processing, or automations of some kind, there's no reason not to use them.
kvr
2009-10-09 16:01:20
@hohonuuli: only if you don't know the language. For somebody skilled in clojure it's easy to read.

Perhaps it's time for Java to borrow some stuff from Microsoft (returning the favor so to speak)
In C# you can do: 
var q = (new [] { "foo", "bar", "baz", "foo" }).Distinct();
There is no way for me to use clojure at work but Java with functional stuff would be great.
Steve Bohlen
2009-12-15 21:55:14
I too am a big believer in the idea of reducing ceremony, but as a long-time LISP developer I think that whether you use as an example something for which there is already a built-in function in Clojure or not, in the end most of your examples here tend to be about LISt Processing tasks which are something that the underlying constructs of LISP are (obviously) well-designed for already :)

Given this, I would *expect* less ceremony in any language when its used for tasks for which 'it was intended' than when using it for tasks where its a square-peg/round-hole problem.  As an example, I start to wonder how much ceremony would start to appear even in Clojure if it were being asked to do some kind of inherently OO work (though I'm not entirely sure what that might be...inheritance, function overriding, encapsulation, ???, ???).

Or is it the case perhaps that while functional *and* OO languages can both process lists (with different levels of efficiency and related ceremony), there just isn't anything 'inherently OO' that I would want to do in functional language like LISP/Clojure...?
Lau
2009-12-15 23:54:52
Thanks to everybody for providing such interesting comments.

@Brenton: I looks like you're relying on the time program on Unix, which is more unreliable than it needs to be. To efficiently test the runtime, use the timers directly from the source. For Scala add println() around the last statement to see the output directly in your shell.

@Sam: Thanks for contributing some interesting examples of how to improve upon the original code.

@Steve: I see you've interleaved questions and statements, so I'm afraid I might miss a few beats. But you're correct ofc that Lisp works wonderfully for List processing, but the fact that most of my programs take great advantage of that is nothing special, in fact about 60%+ of all programs can probably be reduced to some form of List processing. If you want to see how Clojure rolls with imperative OO interop, have a look at my post <a href="http://www.bestinclass.dk/index.php/2009/10/functional-social-webscraping/" rel="nofollow">McSwing meets Enlive</a> for an example - It was painful to write, but it ended up being much nicer than the Java equivalent. You touch on the truth in your last sentence though - Despite the ability to interface with OO code when you need to, Object Orientation is to be avoided at all costs - See Rich Hickeys JVM Keynote a full explanation.