lundi 10 septembre 2012

Clojure for Java/Groovy developers: From GOTO to (recur)

Why this article?

I'm a developer for many years now. I started at 11 when my parents offered me my first computer: an Hector HRX (a French computer in the early 80's).
With it, I learned my first language: BASIC. The version with line numbers and the famous GOTO. A little memory ;)

10 PRINT "HELLO WORLD!"
20 GOTO 10

I learned deeply basic with my second computer, a MSX (I was afraid by the Z80 asm and now I suffer for never learn it). But the first big change occurred with my Atari ST and the GFA Basic. Even if the name of the language contains the 'basic' word, it was close to C. The syntax was very close, no line numbers and no goto. You wrote your functions and called them. And the performances of the GFA basic was good enough for different working. It was an introduction few years later for my C learning.

At the university, I studied the C and C++ languages. In these years, Java was new and the first versions was not very efficient.
With C, I liked to be close to the machine. I'm not afraid of pointers and it's fun to work with the memory.
When I learned the C++, I discovered the OO programming. At this time, I thought "Waaa, the object concepts make easier the programming".
Divide the implementation by objects exchanging messages is near to the formal mindset. I only found the C++ syntax was a little tricky and the multiple inheritance matters more than it solved problems. I don't think the multiple inheritance is bad, but how programmers use it is often not the best.
Thanks to C++ and C, I was ready to learn any other languages because they lay the basics for programming.

While my developer work life, I learned many languages: mainly Python and Java. I learned Java while the end of the Java 1.4 and the beginning of the 1.6 version. For me, the Java 1.6 was the good enough version. Its performances were good and the basics of this languages was fixed.

I discovered the Groovy languages for 3 years and I found it was a good compromise between Python and Java. For me, a language that rests on JVM is a good thing because it's more easy to push it in my company mentality. You generate a jar and all other developers can use your code in theirs. For me, I take less time to code.

Less time to code... It's the main point that did I wanted to take distance with Java. I think Java was a good language for programming. It was a corner stone, like the C, C++, and others. But the programming world keeps on to evolve and I doesn't want to become 'sclerotic' in my thoughts.
Coding in Java has became less and less fun: you write more code for less thing with all frameworks and the famous design patterns. The DP are good ideas but too many people follow them without thinking about them. And we retrieve code with a lot of classes that implement many interfaces with only one method. The code becomes more and more complex to find "what the program does". We lost the main goal of a program: make the job and be easy to maintain.
I repeat, I'm not against the DP. One big point they spread is the delegation over the inheritance.

Today, my main work is to develop server-side program. I don't work on GUI and my programs target data processing. So, I've never had to manage Java swing framework and other ones. My programs are stand-alone or web server applications. According to needs, I coded with C (for very specific needs), C++ (only for maintenance), Java (less and less) and Groovy (when I can).

For a few months, I have been interested for functional programming. I read different articles about this and I found the idea interesting. We go back to the target of a program: the functionality. A lot of articles talked about Haskell. A beautiful, pure functional language but... I wanted to stay in the JVM world to use all the already developed Java libraries. So, I chose to learn Clojure (http://clojure.org).

In this article, I don't detail the functional programming (wikipedia and a lot of others blogs explain the idea better than me). I'm writing about my first experiment with FP: A developer's journey in Clojure and the FP.

What this article is

In this article, there is no code. I give my feeling about Clojure and FP with my imperative mind. I try to share my experiment and, I hope, makes other developers to learn FP and Clojure. I won't talk about the benefits of Clojure in concurrency programming (for now but may be in the future). I chose to describe only the Clojure basics that are those used every day.

How do you code?

An important thing when you learn and use a language is the developing tools. For your knowledge, all main IDEs offer Clojure plug-in (Eclipse, Netbeans and IntelliJ). A lot of Clojure developers use emacs too, but I understand if you think it's too roots. My heart balances between IntelliJ and emacs. I tested the Eclipse plug-in, it works fine but I'm not a big fan of Eclipse. About IntelliJ, don't forget you can use the free community version.

First feeling

Syntax: The LISP way

All people who know *really* FP, please don't take the next sentence in the first degree :) I think Groovy let me to touch slightly the FP by closures. The fact to pass a function into method's arguments open the mind and offers a way to be more generic in objects. So, I want to go deeply into the FP and understand its paradigm.

The first thing, I understood is: learn a language like Clojure is very different than others. When you learn a new imperative language, the main work is a syntax translation. I know it's not limited to that, for some languages we need to understand some principles and the philosophy behind them. For example, when I learned Groovy, I had to move my mind in dynamic spirit and the famous closure logic. But the syntax and the language structure was close to Java.

One issue with a language like Clojure is you can do nothing without a minimal learning stage. The syntax of Clojure is based upon the LISP. It's very particular, all those parentheses. But, when I started learning this syntax, I understood that not regular doesn't mean not efficient. At the beginning, it's hard because we're used to languages based upon C syntax. You must open your mind. Once you did that, you find the Clojure syntax is concise, clear and efficient. And like with all languages, a bad programmer can make unreadable whatever source code :)

Hence, before write any lines of code, I had to read resources. I read the books "Learning Clojure" and "Practical Clojure". It takes a lot of time and it's frustrating. But it's necessary if you don't want to loose time after. So, the first weeks of my Clojure learning was: read books, take notes, test very little code chunks.

New abstractions

Indeed, the syntax is not the main new stuff to learn. You have to adopt new concepts and abstractions. For example, you want a for loop like in other languages. Huh, sorry it doesn't exist. You must ask yourself for what you want to do the loop. It's to compute a result then use the reduce function. It's to process each value in a list, then use map. And so on. It seems strange at the beginning but after some tests and code writing, you realize this kind of thoughts make your code more coherent. When you read again the code, or someone else, you understand *why* you did this code.

Another way in FP to replace loop is the recursion. You think your loops in term of recursion. When you worked for many years with imperative languages, you realize you didn't use the recursion very often. But in FP, and Clojure, you do, you must do. After a little time for lubricating your brain, the use of recursion becomes natural. Like other things, you must train yourself.

Another new abstraction to understand is data structures. As Clojure rests on JVM, you have the standard data structures like maps, lists (vectors in Clojure), set. You have sorted abstractions too for sets and maps. But some of the non-standard data structures are sequences and lazy-sequence. To make simply, sequence is like tuples in Python. Lazy-seq is a great stuff in Clojure. The items are computed while their evaluating. Thus, theoretically, you can have an infinite sequence.

Immutability

An important principle in Clojure (and in FP in general) is the immutability of data. This means you don't change the structure but you retrieve a new structure with the changes. When I read that the first time, I asked myself: "Huh, and the performances?". This vision is wrong because in Clojure, there isn't deep copy. The Clojure is well thought and it uses the structure sharing. It offers better performances even if data are immutable. The principles of the structure sharing is to manage the differences between 2 versions of one data structure. And here, we meet the pragmatic mind of Clojure. If you really need performances, you can switch temporally into mutable structures. You make the job on it and after you return the result in an immutable structure. But in practice, this kind of optimizations is very rare. And don't forget, nothing prevent you to make some code in Java. You'll can call this code easily because we work inside a JVM.

Another thing deriving from immutability, you don't have state. Indeed, each time you change a data structure you receive a new one. It's weird at the beginning but once again, when you start developing in Clojure, that becomes natural. And we'll see later we can manage state :) in some cases (and when it's really necessary).

Functions, functions, functionality

In Clojure (and in FP), all is function. There is no object, no method.
Even in another sort of language, you should avoid too long methods. In Clojure, you can't or it's so hard to write very long function that you don't. That forces you to split your implementation into chunks. What you should do in another languages, you do in Clojure.
And by this way, we come back to the target of programs: meet needs offering functionalities.

The functions are so everywhere you can use them like function result or pass them as argument to other functions. Return a function offers you to adapt your code while its running. Use a function as parameter gives you a way to be concentrated to the functionalities of your program. For example, you want to process fields from a record, we need meet 2 needs: read a CSV file and process data inside fields. First, you write a function that reads the file record by record. This function takes as argument an function that does the processing on the field. Thus, each function meets a precise need and you don't mix the functionality.

This possibility to divide the code offers you a really way for reusing. Because, in OO, we know that the re usability of code is a dreams. While coding, developers adds responsibilities to the objects and their boundaries become blurred. Or, to avoid the coupling, we develop a lot of classes that add the complexity and mask the code's target.

Summary

In this article, I yield only a superficial view of Clojure. I gave only some points that attract me to Clojure.
If you are tired of the Java heaviness and/or you like Groovy, Clojure is a good language to learn. But don't forget: you would have to take a lot of time for learning before appreciate that language. But it's worth.

In the future, I'll write articles about more accurate points in Clojure for Java and Groovy programmers (like how replace inheritance, objects). I'll talk about the concurrency programming too. And this time, there are source codes :)


1 commentaire: