Posts tagged ‘lisp’

I would like to add just a few more arguments regarding the issue of notation.

There is a certain austerity tradition coming from the CS community (at least from the BEST part of it). Most people see syntactic sugar as a waste of time and energy. Furthermore everything is just trees and a linear representation with the root at the head is just fine to represent trees. Lisp embodies this tradition to the full. And for the most part is a great tradition.

This is all fine, and I would understand the defensiveness considered that we live in a world polluted with overly complex languages which just bring problems and no advantages to compensate.

But some level of syntactic sugar is important for humans. And while meta-programming is nice, I suppose most programming languages are still used by human programmers ;) .

It would suggest to have a look at the literature on human cognition, namely the strategies used to read text: it is messy. But I prefer to go in a different direction. I just want to expose how some subtle representation issues might have a massive impact: Have you ever tried to do basic arithmetic with roman numerals? Have a look here, namely “How can I use Roman numerals to do arithmetic problems?”. While this is a different problem, it serves to emphasize that representation matters in the most strangest ways.

Even if it doesn’t, humans are a conservative species, they are not ready to change everything at the same time. Having a to jump to imperative+heteroiconic+infix to functional+homoiconic+prefix is too much. Lisp derived languages loose potential to attract more people. And in this case is is really worth it? Is it really THAT IMPORTANT to be prefixed? Is that the main conceptual selling point of Lisp?

But most importantly there are solutions that are not dirty:.

First nobody is forcing infix notation, one can have both at the same time (check Prolog :- op – you can do BOTH +(1 2) and 1+2).

Second hard-coding operators is not necessary at all: again check the Prolog suggestion. You can have all infix operators that you want (including none)

It is easy to conceptualize a superset of Lisp with infix notation and ZERO INITIAL infix operators.

If I can shout something is this: Check Prolog’s :- op ! Simple, elegant. And fully coherent with the Lisp philosophy at its core.

When you read about programming language comparisons, the main narrative for comparison is normally about the paradigm(s) supported. Lisp, Haskell, Scala, Clojure fall mainly in the functional realm. Prolog is logic. Smalltalk OO. C and Fortran, imperative. Most of them are not “pure” paradigm (e.g. you can make nice OO designed programs in C – just check GTK’s GLib library if you disagree, imperative coding in Prolog, and so on…), but that is besides the point.

The point is that, when comparing programming languages, the main issue of discussion is the bloody paradigm thing.

Paradigm is not really that important! In fact, as said above, you normally can tweak a language to write in your favorite paradigm. Sure the ability to do that varies from case to case, but in most cases that I can think of, it is really not difficult to cross paradigm boundaries. In fact, I would go as far as to argue that it is easier to do proper OO design with C using GLib then with the highly complex and convoluted C++.

Before going into the fundamental point that I want to make, I would also note that ecology matters: Are there good libraries? Good documentation? Does it run on a virtual machine? Portability? Nice community? User base? That is, when comparing programming languages all that is around the language is more important than the language itself. Just ask all the poor of us poor Prolog/Lisp/Haskell fans why are we doing Java/C++ during most of our day? It puts bread on the table, and, for the most of us, that is the most important criteria (I prefer not to starve!).

But, going to the main point here, I would like to propose that one of the fundamental points in comparing programming languages from a technical standpoint is homoiconicity.

Just to remember, an homoiconic language is a language where the program is represented as the core language data-type. Code is a data type.

If you classify languages according to homoiconicity, then they split in completely different ways:

  1. The homoiconic bunch: Lisp, Prolog, Ioke, Clojure, …
  2. The non-homoiconic bunch: Cobol, Fortran, C, Java, Goovy, Scala, Haskell, OCaml, [A very long list follows]…

From this point of view, the comparison of say, Clojure to Scala as sister-languages makes little sense, as they fall in different groups.

Homoiconic languages lend themselves to – by construction – metaprogramming and extensibility (think very easy embedded DSLs). And some of these features are difficult (with varying levels of difficulty) to implement in non-homoiconic languages. At best (as “best” I am thinking of some scripting languages like Python), they are awkward to do in a non homoiconic language.

As a side jab, last time a checked, Scala was very very poor on metaprogramming (has that changed?), making it the only “modern” language which seems to be scorning metaprogramming. Scala can still be DSL-extensible (I offer my own example both in Scala and Grovy: Ronald: A Domain-Specific Language to study the interactions between malaria infections and drug treatments.

One could argue of the value of doing programs that reason about themselves (and that idea has very bad karma coming from assembler – an idea so old and so disconnected from current reality that I am not even going to discuss it). I am surely on the side that proper metaprogramming is one of the core features of any elegant, productive and declarative solution.

Also, a very nice side effect of having code as data, is that the syntax of homoiconic languages is normally very, very simple (as in trivial to learn). This is just a side effect, but compare this with the learning curve of, say, C++ syntax. There is also a philosophical issue here: you get a simple, highly flexible environment, where complexity is tacked not by having a complex mammoth that tries to address all possible cases, but by a set of plastic, bendable building blocks.

Homoiconicity is not a black-and-white feature. For instance, Lisp macros are not first-class objects (I am a Clojure newbie, so feel free to correct me) so you cannot metaprogram with them. Prolog seems to come close. In fact, to a Prolog programmer, Lisp macros seem especially inelegant as the are “out of the system”.