Why I love Common Lisp and hate Java, part II – code examples

Writing programs that write programs.This is a sequel to my previous post where I urged those who gave up on programming — probably because of the spoon-fed association with Java and stress — to give coding another chance with a whole “new” (read: different) approach: Common Lisp. The purpose of this sequel is to address the open-minded skeptic, unconvinced yet unafraid of paradigm-shifting change. Common Lisp is not just another language, it is a different way of coding.

While I tried to make a point that the REPL completely alters the experience of coding — which can only be experienced and not by reading a blog post — this time I will try to showcase Common Lisp’s powerful meta-programming through some example code.

Writing programs to write programs is mind-boggling if you come from the imperative world of Java. Simply because it is not possible in Java, therefore not taught, hence not even considered as a powerful way of abstraction and code reduction. We write methods and functions to abstract away reoccurring computational patterns. Why not write functions that take the abstraction level even higher and abstract away coding patterns?

Suppose we write a method in Java that returns the maximum value given an array:

public static int getMaxValue(int[] numbers) {
	int answer = numbers[0];
	for (int i = 1;i < numbers.length; i++){
		if (numbers[i] > answer) answer = numbers[i];
	}
	return answer;
}

And it’s equivalent in Common Lisp (ugly Lisp code beware: I’ve tried real hard to keep it as imperative and iterative as possible for our fellow Java coders):

(defun get-max-value (list)
  (let ((ans (first list)))
    (do ((i 1 (1+ i)))
        ((>= i (length list)) ans)
      (when (> (nth i list) ans)
        (setf ans (nth i list))))))

Now what do we do when we want to write a function that will return the minimum value? Simple, just copy-and-paste the code, rename the method name and change the predicate:

public static int getMinValue(int[] numbers) {
	int answer = numbers[0];
	for (int i = 1;i < numbers.length; i++){
		if (numbers[i] < answer) answer = numbers[i];
	}
	return answer;
}

That’s all there is to it, right? Now this is when most of us would get up for another cup of Java, while deliberately unintentionally keeping their screen on and filled with lines of code — a sense of false but incentivized productivity.

Lispers get itchy. Good coding practice is all about re-using code and minimizing code duplication, so whenever our laziness brings us to copy-paste, our Lisp intuition tells us it is a bad short-term solution. Using copy-paste means that there is going to be a large chunk of code that will be duplicated, which needs, should and most importantly CAN be abstracted away in Common Lisp. As a matter of fact, there are two ways to do this: write a macro, or write a function that will accept the predicate as a parameter.

Let’s start with the latter, since it’s easier to grasp. Common Lisp allows methods (Java jargon) to accept other methods as parameters. It is even possible to return methods as a result of a method call. Let’s see how we can apply this to writing the above in Common Lisp:

(defun get-from-list(list pred)
  (let ((ans (first list)))
    (do ((i 1 (1+ i)))
        ((>= i (length list)) ans)
      (when (funcall pred (nth i list) ans)
        (setf ans (nth i list))))))

We just add another parameter called pred, and changed the greater-than sign to a function call to pred. Now we can define both get-max and get-min using the above:

(defun get-max(list)
  (get-from-list list #'>))

(defun get-min(list)
  (get-from-list list #'<))

Isn’t that beautiful? Let’s take a second to soak up the elegance.

Meanwhile, let’s do that again, but this time with a simple macro. Note that it is generally bad practice to use macros where functions suffice. The following is just an example to warm up your meta-minds, before I show you another example where macros prove truly invaluable.

(defmacro get-from-list(list pred)
  `(let ((ans (first ,list)))
     (do ((i 1 (1+ i)))
         ((>= i (length ,list)) ans)
       (when (,pred (nth i ,list) ans)
         (setf ans (nth i ,list))))))

The easiest way to get your head around macros is to consider it as boiler-plate code, where you plug in your pieces of code by using the parameters. Whatever you provide to the first argument in the above, will be plugged into the code (at compile time) wherever you see ,list. The same goes for pred, so we can now define get-max and get-min again with:

(defun get-max(list)
  (get-from-list list >))

(defun get-min(list)
  (get-from-list list <))

Do I see a smile, Mr. Java?

Notice the subtle difference; since we use macros, unlike the previous example where we provided a function as an argument, we are just passing along pieces of code. The #’ notation depicts a function, so we drop that, just like we don’t need to funcall on the predicate. The get-max definition will compile behind the screens into identical code as the get-max-value definition a few page scrolls above.

The best part is if you need to adjust the function, e.g. to ignore null values in an Integer array. That’s when Java gets real messy. You don’t do that. The whole point of declaring variables is so that you can change it in one place. Why, then, do you change functions in multiple places and not complain?

Actually, I have one more example to share with you that got me sitting up straight in euphoria, when I was writing some test suites for Open-VRP, but since there is enough to digest for today — a paradigm shift is hard to come by — let’s leave that for another post.

Realizing and understanding that you can use a macros to code, feels a little like obtaining your driver’s license. Not only are there now many more ways to get there, but places that were inaccessible before suddenly become destinations.

Continue to Part III – macros


I am sure there are plenty of great Lispers out there who have done some strong meta-programming. Feel free to send me a link to your favorite meta-hack example and I’ll add it below.

About these ads

36 thoughts on “Why I love Common Lisp and hate Java, part II – code examples

  1. have your read the ‘Land of Lisp’ book? It is just fo beginers but it had a very fun and “hello java do this -‘ when it squashed an entire functional with ribots and bearable grafics game into ONE A4 PAGE OF CODE.
    (defun robots ()
    (loop named main
    with directions = ‘((q . -65) (w . -64) (e . -63) (a . -1)
    (d . 1) (z . 63) (x . 64) (c . 65))
    for pos = 544
    then (progn (format t “~%qwe/asd/zxc to move, (t)eleport, (l)eave:”)
    (force-output)
    (let* ((c (read))
    (d (assoc c directions)))
    (cond (d (+ pos (cdr d)))
    ((eq ‘t c) (random 1024))
    ((eq ‘l c) (return-from main ‘bye))
    (t pos))))
    for monsters = (loop repeat 10
    collect (random 1024))
    then (loop for mpos in monsters
    collect (if (> (count mpos monsters) 1)
    mpos ;; Do not move if monsters are dead
    (cdar (sort (loop for (k . d) in directions
    for new-mpos = (+ mpos d)
    collect (cons (+ (abs (- (mod new-mpos 64)
    (mod pos 64)))
    (abs (- (ash new-mpos -6)
    (ash pos -6))))
    new-mpos))
    ‘ (count mpos monsters) 1)) ;; All the points where a monster is have 2 or more monsters
    return ‘player-wins
    do (format t
    “~%|~{~~}|”
    (loop for p
    below 1024
    collect (cond ((member p monsters)
    (cond ((= p pos) (return-from main ‘player-loses))
    ((> (count p monsters) 1) #\#)
    (t #\A)))
    ((= p pos)
    #\@)
    (t
    #\ ))))))

    There it is. Looks complicated, I know, but hey, that’s life :)
    I wonder how big the java version would be ;)

  2. There’s at least one thing I think Common Lisp should learn from Python:

    hash[index1] = vector[index2]

    becomes

    (setf (gethash index1 hash1) (elt vector index2))

    in Common Lisp… (notice the parameter order and naming in Common Lisp and the awesome symetry in Python)

    This is not to say that Lisp isn’t great, what I mean is that there are other great languages out there.

  3. ;can condense a bit more:
    (defun get-max-value (lst)
    (reduce #'(lambda (a b) (if (> a b) a b)) lst))
    ;or
    (defun get-max-value (lst)
    (apply #’max lst))
    ; could easily pass in the #’> or max

    • That’s correct, the whole function wouldn’t even be necessary because of apply and reduce. But that would defeat the point of the post. Furthermore, you wouldn’t be able to adjust the function, such as accept a list with NIL values and ignore them.

  4. I’m a Java/C# programmer, I’ve learned some Haskell at college and some Scheme by myself. I understand that some common Java problems can not even be expressed in Lisp, I understand Lisp code to be always shorter and many times more expressive and readable than Java code. I understand the the idea of functional languages being slower is completely wrong nowadays. I also think that the average Lisp programmer is smarter than the average Java/C# programmer like myself.
    But I’ve always found that functional programmers choose to show their skills in one of two ways:
    1 – Showing how a common simple task can be done better and nicer, like this post.
    2 – Showing an incredible abstract concept (something like “lets make a Y combinator with monads and homeomorphic transformations”) I’m not even close to understand.

    Why can’t you (not you specifically, but the functional programmer community) build a great usable program and show the world the real benefit of using common lisp or haskell or whatever?
    I mean, choose any usable software, like a web browser, a word processor, a chat client and duplicate it using common-lisp. Create a product my mom can install, use, and enjoy, and show that a small team of developers, using the best tools, can do it better, less buggy, and faster or at least as good as a bigger group of average java/c++/c# programmers.

    Isn’t that the real test for a programming language?

    What about a RDBMS? I’m used to MySQL, which is coded in c or c++, I don’t know, and I access it from my java programs without knowing anything about how it works. Create another RDBMS, with the same interface to the external world, using common lisp. If it is really good, fast, compatible and bug free it will be used, and then help Lisp to gain attraction again.

    This is not a challenge in the “I bet you can’t do that” sense, but in the “I hope functional languages will rise someday” sense. I personally hate when I need to use the awful Java syntax for anonymous functions, I would love to work within a functional paradigm, but I can’t push something in my workplace if I don’t have a success story to tell.

    Besides that, we all know Java is specially ugly when passing functions around, there are lots of better languages in the JVM, even C# can do it better, and when Java finally gets clousures (next year I dream) we will have a nicer way to do that. Until then, you need such big bunch of lines to pass a method around that copy/paste is better sometimes.

    • Hi Pablo,

      Thanks for sharing your thoughts. I agree with that when people write about the advantages of Common Lisp, they use simple abstract advantages to do something you cannot do in another language. I also think that there is nothing wrong with that — I think it is the quickest way to get to the point and leave the reader to think either “so what?” or “interesting, now what can I do with that?”

      In terms of usable software; there hasn’t been many, but certainly enough to prove the point that it’s possible. Emacs, for instance is a text processor that takes some time to getting used to, but now I use it not only to develop Common Lisp in, but also to write Latex documents. Paul Graham wrote extensively on how Common Lisp gave him the advantage to beat the competitors in the e-commerce business with Viaweb. Probably the most successful commercial application of Lisp, AFAIK, is the engine behind ITA software, recently acquired by Google. In terms of databases, have a look at CLiki’s databases page.

      Most importantly, don’t just trust what I say. Seek the truth for yourself.

      Cheers,

      Marc

      • If you had a PlayStation 1, you probably had Crash Bandicoot. If you didn’t, you may have had one of the Jak and Daxter games.

        These were both written in Lisp. Not common lisp, but dialects which the lead developer created himself specifically geared towards game objects, (he called it GOOL)

      • Hi Marc

        Excellent lisp related posts.

        Another set of highly successful applications in Common Lisp are available in Franz and Lispworks pages.

        At last count, the total was 95 (69 + 26).

        Samples: http://www.2is-inc.com, Inc’s 2011 fastest growing listee uses Lisp, Ravenpack, SRI, Aura, Memetrics, Lissys Ltd – Aircraft Analysis, Liberating Insight and goes on.

        I am in no way affiliated to either of them. Just to point out what CL can do and has been doing over the years, When CL developers talk of commecially successful CL apps, they start out with apologetically (not intentionally), implying that ITA and Emacs are the only two successful apps, which is not true.

        Also, it is noticeable how many “Language” vendors make their living by selling “Language” and “Runtime” licenses?

        Take care

        Muthu
        =====

  5. and like that?

    public class CommonLispAndJava {
    public int getFromList(int[] numbers, char sign, int answer) {
    for (int i = 1;i < numbers.length; i++){
    if (numbers[i] < answer && sign==' answer && sign==’>’ ) answer = numbers[i];
    }return answer;}

    public int getMin(int[] numbers) { return getFromList(numbers, ”, numbers[0]); }

    public static void main(String[] args) {
    CommonLispAndJava d = new CommonLispAndJava();
    int[] numbers = {5,3,10,4,1,6,2,8,7,9,15};
    System.out.println(“Max? “+d.getMax(numbers) +”, Min? “+d.getMin(numbers));
    }
    }

  6. There two problems with your get-from-list macro:

    Multiple evaluation: if someone calls your macro as
    (get-from-list (some-expr) some-pred),
    then (some-expr) may be evaluated multiple times.

    Hygiene: if the predicate is a local function called “ans”, as in
    (let ((ans (lambda …))) (get-from-list … ans))
    your macro fails.

    • Very true points, thanks for pointing it out. The point of the article is to stir the meta-minds, to raise awareness of the possibility of meta-programming — throwing in gensyms I deemed distracting. I am not writing a tutorial on meta-programming (there are plenty of good books/articles out there). It is intended as a teaser to get an idea of what’s possible, rather than actually teaching macro-writing. To peak enough interest for people to start their own journey of discovery.

    • Don’t worry Dave; ask any Lisper and they’ll tell you we don’t look at the brackets just like you don’t count curly brackets or semi-colons — it’s the indentation.

      They do look confusing at first, but you’ll get used to them quite quickly.

  7. Great post, thank you. Here is afew different version of get-from-list method I came up with.

    ;;recursive (tail recursive would be alot better)
    (defun get-from-list (lst p)
    (if (null (cdr lst))
    (car lst)
    (let ((rest-val (get-from-list (cdr lst) p)))
    (if (funcall p (car lst) rest-val)
    (car lst)
    rest-val))))

    ;;iterative with do* statement
    (defun get-from-list (lst p)
    (do* ((l (cdr lst) (cdr l))
    (selected-val (car lst) (if (funcall p selected-val (car l))
    selected-val
    (car l))))
    ((null (cdr l)) selected-val)))

    ;;iterative with reduce like Issac Trotts suggested
    (defun get-from-list (lst p)
    (reduce #'(lambda (x y) (if (funcall p x y)
    x
    y)) lst))

    • Thank you for your input. The Lisp code in the post is indeed quite ugly; I wrote it just like that to reduce distractions from the point. Here is where I actually used this function (getting min/max while ignoring NIL from list) and it’s tail-recursive.

  8. So, I should give up a top notch VM, a huge community, the most job offers than any language, and tons of libraries, to run a so-so language (Common Lisp) because it can change the token for comparison?

    I could do the CL example in Java two, with a little more code because of lacking first class functions. No “duplication” needed as in the example. But I could also use Scala, Closure and a ton of other Lisp-y like languages for the JVM.

    That said, the efficiency of writing toy examples like “max” and “min” rarely matters in actual development.

    That’s why there are tons of huge systems built in Java and millions of programs, OS s etc written in C/C++, while all Lisps have to show for is a few AI stuff, some internal tools by lisp geeks, and Emacs. Oh, maybe ViaWeb version 1, too.

    • The VM is top notch – Scala & Closure I’m sure are great languages as well. You are clearly on top of things, so not really my intended audience, but thanks for your input.

      “That’s why there are tons of huge systems built in Java and millions of programs”

      But are you then also saying that Microsoft Word is “great technology”?

      In terms of commercial successes, what about ITA Software?

    • There are (at least) two kinds of people dealing with programming languages. Those who love coding and want to improve the way it can be done and make it more useful, and those who just want to get a job and “get things done”. Both are eligible – in the end, the first kind creates tomorrow’s tools for the second kind. Therefore, the first kind needs to have a widely opened mind for new concepts, while the second kind needs to be rather conservative.

      You obviously belong to the second kind. Lisp is not for you, and you will never be productive with Lisp, because for most fancy new spreading “technologies” you will find the Lisp community not being interested, while you will find a Java Library which is well-tested and well-maintained.

      I furthermore recommend reading http://www.winestockwebdesign.com/Essays/Lisp_Curse.html

      Last but not least, I think you missed the point about macros. Java’s lack of macros is something even C programmers criticize. Lisp’s macros are a very powerful tool with which you can even define your own control structures, but unfortunately, the blog post did not really point that out yet. I look forward to its follow-ups.

      • Interesting thoughts and a great essay.

        CL is not a panacea and certainly not for everyone. It is, unfortunately, a neglected alternative. I see the point of it’s so-called curse. A pity though, since there isn’t anything really holding Lisp back from writing well-documented and large collaborated projects. Though I agree with the essay to some degree, I think you shouldn’t blame the SUV for reckless driving.

        As for me personally, I am grateful for CL for having re-invigorated my coding passions, mostly due to its pleasant and engaging experience. Though Java has its merits and a large number of libraries available, it couldn’t keep me intellectually challenged and wired in.

  9. Thanks for sharing your code in your respective favorite languages and raising my awareness of what’s out there.

    I’m not a polyglot by any means, so I’m in no position to claim that Common Lisp is the best language in the world. The point, however, is to help people realize that programming is not all about Java, which has been an enlightening realization that I’ve been going through for the past year, for which I feel an urge to share.

    Last weekend I had sushi with a few friends, one of whom studied Software Engineering, but decided that a career in programming wasn’t for him, because he didn’t enjoy it. The things he complained about? Searching for brackets, typos, verbosity, basically frustrating. The language he was taught at university? Java.

    Oh my god, me too!

  10. in the K / q languages
    q){$[x>y;x;y]}/[2 6 8 9 1 3]
    9
    q){$[x<y;x;y]}/[2 6 8 9 1 3]
    1

    Shorter isn't necessarily always better. Right tool for the right job.

  11. To stay functionally pure (no side effects like changing the value of a variable), you can actually describe this as a fold.

    The basic idea in Haskell is:

    getFromList _ [] = error “requires a list with at least one item”
    getFromList choose (x:xs) = foldr choose x xs

    If you aren’t familiar with the syntax, the first line throws an error if the list is empty, otherwise it applies a supplied “choose” function to each two elements recursively, ultimately returning a single value. Your max and min definitions then become:

    getMax = getFromList max
    getMin = getFromList min

    In common lisp I believe there’s an equivalent, though it may be called reduce instead of fold.

  12. Here’s what it looks like in Haskell:

    $ ghci
    Prelude> let getFromList ls pred = foldl (\x y -> if x `pred` y then x else y) (head ls) (tail ls)
    Prelude> getFromList [1..10] ( getFromList [1..10] (>)
    10

  13. Nice series of articles. Just to be fair, you should notice that abstracting away getMaxValue and getMinValue could be done with interfaces. It would need muuch more code and wouldn’t be even near of CL elegance, but it’s possible.

  14. Anonymous inner classes aren’t so bad in lieu of functions as first-class citizens!

    public class CommonLispAndJava {

    abstract class Predicate {
    abstract boolean choose(int alpha, int beta);
    }

    public int getFromList(int[] numbers, Predicate predicate) {
    int answer = numbers[0];
    for (int i = 1;i beta;
    }
    });
    }

    public int getMin(int[] numbers) {
    return getFromList(numbers, new Predicate() {
    @Override
    boolean choose(int alpha, int beta) {
    return alpha < beta;
    }
    });
    }

    public static void main(String[] args) {
    CommonLispAndJava demo = new CommonLispAndJava();
    int[] numbers = {5,3,10,4,1,6,2,8,7,9};
    System.out.println("Max? " + demo.getMax(numbers));
    System.out.println("Min? " + demo.getMin(numbers));
    }
    }

    • It takes you more *lines* in Java than *characters* in Lisp to say “less-than”.

      People have different ideas about what constitutes “not so bad”.

      • Yeah, and it probably takes 3-4 characters in J for the whole Lisp program. Maybe even 1.

        But the Java program is much more readable, and all of it’s length is due to Java not supporting closures, which it will get in Java 8.

        • No, the Java program is much less readable due to the irregular syntax of Java as opposed to the s-expressions of lisp.

What say you?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s