Intriguing comment on a Lisp book

I found this comment on a lisp book called ANSI Common Lisp by Paul Graham from PH:

“With macros, closures and runtime typing Lisp transcends object-oriented programming. If you understood the preceding sentence you probably should not be reading this book.”

A closure is something like this:

; Lisp
(defun addn (n)
#’(lambda (x)
(+ x n) ))

This is a function that takes n as an argument and return the function x+n (not the result but the function).

A macro is a function that works on the language level and returns lets people build functions that build lisp expressions.

Runtime typing you know what it is.

We could take the comment has an exageration typical of people who just want to sell their fish. But that would be the easy way to dismiss that comment.

Giving it a little more thought: OO programming has a lot of type-checking at compile time but also a lot of runtime typing. Compile time type-checking as well as inheritance and dynamic binding are some of the strongest arguments of OO languages. With Lisp macros we can simulate compile-time type-checking and expand it as far as we want. Since Lisp supports closures, dynamic binding would be a piece of cake. In fact Lisp can emulate almost anything from OO with what the author mentioned in the above quote and still leave the choice of expansion to the user.

Its funny that the guy who made the javavm was also the author of a well known editor that used a version of lisp as a macro language to expand the editor that become one of the most successful in Unix world.

So my question is why do we need Java, Eiffel and C++ when we have Lisp ? If Lisp transcends OO then we should be using Lisp not Java. We could make a Lisp interpreter/compiler to the java vm that in theory would do everything Java does or is it not so ?

One word… productivity…

I used LISP at univ many many times. And it is incredible powerful but unfortunate falls under the same as perl. A week after you written your smart function you need the same amount of time to understand what the **** you were doing. And trying to understand another persones code is doomed. So Java has a big advantage.

There is one big difference between Lisp and Java: Java has static type checking. Opinions differ if this is good or bad, personally I like it. IMHO Lisp is way too heavy on the parenthesis, a Java program is easier to read. But you can’t beat the simplicity and elegance of the Lisp programming language.

Of the newer languages to appear I think D (http://www.digitalmars.com/d) looks interesting. It’s a statically typed language and contains a mix of the best features from Java and C++. Some of its nice features which are missing in Java are delegates (closures), contracts, real templates etc. But it also lacks some nice Java features like dynamic class loading, reflection (it has some runtime type info), boolean (!) and weak references. Hopefully it can replace C and C++ at least.

Lisp being hard to understand also means you will be less likely to make mistakes since you will need to be very focused on what you are doing to work with it.

Type-checking would not be a problem either. Lisp programs are lists. Your program is a data structure that can be manipulated by Lisp. So if you want to do type-checking you only have to create a lisp program that will do one or more passes on the program you want to check:

; type-check it
(type-check my-program)
; compile it
(compile my-program)
; run it
(my-program)

After looking at almost every kind of prog language out there, im convinced that all the tricks like static type-checking, inheritance and generics are just programs that take has input another program and validate the assertions we put on it before the program is compiled.
Lisp lets you do your own type-checking, generics or whatever while for a compiler like Java the algorithm used for it can only be changed by Sun.

Im considering doing something like a Lisp compiler to the Java vm. It would be cool to work my own type-checking and trying things like dynamic code generation (this stuff exists in Lisp) where you can compile classes to memory and use them immideatly. I believe this would solve a lot of problems with java generics without having to mess with the vm.

[quote]Lisp being hard to understand also means you will be less likely to make mistakes since you will need to be very focused on what you are doing to work with it.
[/quote]
Yea, right, and this rule also applies to machine code.

And Java programs are just sequences of chars or bytes which can be manipulated in Java. What’s your point?

Well, static type checking isn’t as easy as you suggest, especially when the types are not specified in the program. Consider this Lisp example:


(defun addOne (x)
  (+ x 1))

Since the type of ‘x’ is not specified this function can be called with an argument of any type, but it will only work for numbers as ‘+’ is not defined for other types (I believe this is the case in Lisp). So, everywhere ‘addOne’ is used you have to check that the type of the argument to ‘x’ is valid. This is what advanced programming languages like ML and Haskell does.

I think tricks is a bad name and the program you refer to is often called a compiler. The only thing you have accomplished is putting the compiler inside your program.

[quote]Lisp being hard to understand also means you will be less likely to make mistakes since you will need to be very focused on what you are doing to work with it.
[/quote]
:). Not even slightly, I’m afraid. Real-life experience shows time and time again that what actually happens is just … you are MORE likely to make mistakes because you are generally unlikely to put extra effort into programming something that ought to take X amount of work. This happens to everyone, even the most diligent, though less the more willing you are to waste huge amounts of time on relatively simple tasks.

So…what actually happens is that your code is “no more buggy with LISP” if and only if your productivity is considerably reduced.

So…LISP makes your code more buggy, or it makes it take longer to program, and usually both. Usually, it’s other weirdnesses make it take longer to program for independent reasons.

So, all in all, productivity is usually terribly low with LISP. Some places, where it’s uniquely suited to your algorithms, it makes up for this by hugely increasing productivity elsewhere, but most of the time it doesn’t.

Maybe i didn’t explain myself well. I consider recursion and closures a superior programming technique. Its only hard until people get used to it, after that is programming without those techniques that makes it hard. Just imagine handling awt events without inner-classes.

You have annotations in lisp almost since the time it was invented. You can attach any structure to any simbol of your program. With this trick its possible to establish a convention for giving types to simbols.

Using your example:


(defun addOne (x)
  (+ x 1))

You could expand it to have type info annotated in it. Supose you have two functions to annotate a simbol:

; takes a simbol and returns it
; annotated with several key=value pairs
(put simbol key value …)

; gets a simbol annotation
(get simbol key)

With this you can now rewrite your function like this:


(defun addOne ((put x 'var-type 'integer))
  (+ x 1))

When you call (type-check my-program) the type-check function has enough information to check your program just like a compiler would.

The main programming technique used in lisp, that is possible with Lisp features, concists in rewriting the language. That is recreate the language for the problem your program is trying to solve. So it makes sense that we write a compiler inside our program.

This may sound a big effort at first but considering the time it takes to write a complex application like a software rendering engine it may be well worth the effort. Most of the complexity of compilers is on the rich sintax languages provide and on the optimization stages. Lisp sintax is so trivial that anyone with bare knowledge of programming could do a parser for it. With annotations you can possibly attach any information a modern compiler does to the abstract syntax tree after parsing the source. So in theory it would be possible to do anything in Lisp that anyother language does with the benefict of being customizable.

From my limited reading about it, when you have mastered Lisp you can write very powerful programs that pretty much rewrite themselves according to your requirements and you can do it easily.

From my limited experience of using it, mastering Lisp is the work of a lifetime…

Thats one point against Lisp. Unfortunatly Lisp gurus don’t help much on making promoting the qualities of that language as it shows by this link from a famous Lisp book author:

http://www.paulgraham.com/javacover.html

Arrogance is all over this article, where Java is badly criticised and compared to fast-food. Some people tend to think that because their language of choice is complex and powerful this means everyone should sweet the hell out of learning it. These guys knowledge of usability and accessibility is indirectly proportional to their knowledge of Lisp.