
Clojure: It’s About the Libraries - coglethorpe
http://stuartsierra.com/2009/02/22/its-about-the-libraries
======
asciilifeform
Clojure revolts me.

It is the most explicit to date abandonment of the age-old Lispers' Dream,
which was "Lisp All The Way Down." Clojure is the antithesis of the Lisp
Machine. Rather than a crystalline pyramid of _comprehensible_ mutually-
interlocking concepts, behind every Clojure primitive there lurks Black Magic.
The Clojure user who is missing some routine or other will run crying to Java
for help, rather than implementing the feature himself _correctly_ \- that is,
as a natural part of the entire language, built on the same concepts. Clojure
pisses on everything I've ever loved about Lisp. It rejects even what little
consistency and intellectual rigor there is to be found in an abomination like
Common Lisp.

Clojure is the False Lisp, which Reeketh of the Cube Farm.

I don't care if everybody really _is_ more productive in Clojure than in
Common Lisp. The latter is not my standard of comparison (Symbolics Genera,
the state of the art, is. Or, if you want something that is distinctly
inferior but is currently available on the market: Mathematica.) Clojure is
the gutted corpse of a dream.

I am tired of this abomination being hailed as the future of Lisp. Users of
_real_ Lisps, such as myself, will keep hoping, dreaming, and working on
systems which do not betray the original virtues of the language.

~~~
weavejester
Please tell me this is a parody. A programming language is a tool, not a
religion.

~~~
ken
No, a language is a way of communicating ideas, and hence, of thinking about
them. (I wouldn't call English or kuchi shoga or tensor diagram notation
"tools", even though they can be incredibly useful.) A programming language
implementation can be used as a tool.

I think this is the core of our differences. Lisp has traditionally been used
mostly as a language -- as Dijkstra put it, it "has assisted a number of our
most gifted fellow humans in thinking previously impossible thoughts". Most
other programming languages have been used as tools.

Clojure looks like a perfectly competent Lisp-on-JVM (with immutability!), but
I don't see it changing how I think about anything. It's thoroughly on the
"tool" side of things, which understandably leads to people in the "language"
camp being miffed that anybody thinks it's comparable to classic Lisps from
the "language" camp.

The Lisp engine in Abuse was a tool, too, and highly productive for its uses,
but at least nobody claimed it was a successor to the Lisp line.

~~~
weavejester
I dislike arguments over semantics. Saying something is a tool does not mean
it is not also a language. For instance, mathematics can be considered both a
tool and a language.

It's true that Clojure is a programming language designed to be practical, but
I fail to see why this would make it any less useful as a language for
communicating ideas, or any less able to change how people think about things.

Could you provide an example of an idea that is more easily communicated in
another Lisp, rather than in Clojure?

------
herdrick
_‘Cause if it’s ever been done, anywhere, by anyone, someone’s done it in
Java. Twice._

If only. If I could get something like Python's Numpy on the JVM, I'd be using
Clojure on my current project(s).

~~~
icey
I don't know how useful this is to you, but here is a list of Java numerics
libraries (and assorted other information):

<http://math.nist.gov/javanumerics/>

~~~
herdrick
I mean, "something as good".

~~~
swannodette
It's always good to do your research before making a statement on a topic you
might not have a complete picture of:

Colt: <http://acs.lbl.gov/~hoschek/colt/> Parallel Colt:
[http://sites.google.com/site/piotrwendykier/software/paralle...](http://sites.google.com/site/piotrwendykier/software/parallelcolt)

There's been talk about integrating this functionality into Clojure. Incanter
is an example of a project by someone who wanted to get primitive support for
matrix math and has had quite a bit of success.

~~~
herdrick
Wow, Incanter looks great. I've got to look into this more.

How do you know I don't do my research by making provocative statements on
public fora?

~~~
jimbokun
"How do you know I don't do my research by making provocative statements on
public fora?"

There is something to be said for that. I would not have thought to Google for
"R-like interactive environment, built with Clojure and Java charting and
numerics libraries." But now that I know it exists, I'm pretty excited about
the possibilities.

------
brlewis
The impedance mismatch between Scheme and the JVM is a lot less than what the
writer thinks. Here's the comment I just added to the post:

You don’t need primitive-static-method in Kawa as of several years ago. It’s
just there for backward compatibility. Newer syntax for calling Java methods
is much easier:

<http://www.gnu.org/software/kawa/Method-operations.html>

~~~
asciilifeform
> The impedance mismatch between Scheme and the JVM is a lot less than what
> the writer thinks

Tail call optimization? Scheme is a cruel parody of itself without it.

~~~
brlewis
I can only remember two cases where I had to turn on the full-tail-call option
to the Kawa compiler, and even then performance wasn't a problem. The SISC
Scheme interpreter does reasonably well too, and it has full tail call
optimization all the time.

------
benreesman
Using Java libraries from a non-Java language on the JVM is one of the
happiest parts of my day, every day.

However that being said, the real reason why Clojure is going to become the
most important Lisp is the same reason why Java has been displacing the
theoretically-faster C++: multicore.

~~~
10ren
You're claiming that (a) Java is better at multicore than C++; and (b) Java
has been displacing C++; and (c) that the former is due to the latter. I
haven't heard this idea before. Can you elaborate please?

Threading the locks have been integrated into Java from the beginning, with
every object having a monitor and functions like _wait()_ and _notify()_ , and
a _synchronized_ keyword. These are nice, and do help, but they don't solve
the problem. I've heard that Java fixed up some problems with these in version
1.5 or 1.6, but haven't looked at the details.

My understanding is that none of the imperative languages are very good at
multicore. Erlang is said to be effective at it (because of pure message
passing); and some people claim FP will help because it overcomes the problem
of shared state by making it immutable (while this is true, I'm not convinced
it's particularly helpful in large projects, in practice).

So I'm interested in your reasoning.

~~~
benreesman
As limited as the threading model of synchronization is, it can be used to
fairly easily write programs that scale up to some reasonable number of
threads (10-100). This is less to do with the convenience of having keywords
like 'synchronized' and more to with the fact that modern Java has a proper
memory model. The C++ people are trying to put together a memory model, but
it's not here yet and there's some doubt about the ability to integrate it
successfully with existing (pthreads etc.) code.

Without a memory model you're going to be writing more code that is less
correct at a substantially higher cost. If you're interested in this google
for a Google Tech Talk by Josh Bloch on 'Java Memory Model'. This basically
comes down to my ability to get at architecture specific stuff (CAS, fencing)
in a platform independent way and have it work. Cliff Click has a really neat
tech talk on writing a lock-free hash table in Java, don't bother trying to
write it in C++.

Ultimately we will need a better model for concurrency, which will be some
combination of functional programming and lightweight processes (actors).
Erlang/Scala/Clojure/Haskell are in the right neighborhood (maybe Gambit
Scheme, don't know much about it), but Erlang and Haskell are really hard to
teach to mere mortals like myself. I don't know enough category theory to
understand 'hello world' in Haskell, but I can write Scala and Clojure
programs that work (and leverage my existing investment in the JVM).

edit: i left off something imporant. if anything saves imperative programming
it will be transactional memory, which is _exremely_ hard. hardware TM and
code written for TM are in a chicken-and-egg situation. the answer is hybrid
hardware/software TM and the sun guys are way ahead on this too.

~~~
arohner
_if anything saves imperative programming it will be transactional memory,
which is exremely hard. hardware TM and code written for TM are in a chicken-
and-egg situation. the answer is hybrid hardware/software TM and the sun guys
are way ahead on this too._

What's interesting is STM is only hard in imperative languages. It's
relatively straightforward in Clojure and Haskell. See
[http://enfranchisedmind.com/blog/posts/the-problem-with-
stm-...](http://enfranchisedmind.com/blog/posts/the-problem-with-stm-your-
languages-still-suck/)

~~~
zzygan
Also recently there was a very interesting article in Communications of the
ACM about STM vs HTM and the problems with both in a general sense.

[http://delivery.acm.org/10.1145/1410000/1400228/p40-cascaval...](http://delivery.acm.org/10.1145/1410000/1400228/p40-cascaval.html?key1=1400228&key2=9950411421&coll=ACM&dl=ACM&CFID=33768312&CFTOKEN=64607598)

Edit: Prettier version
[http://mags.acm.org/communications/200811/?folio=40&CFID...](http://mags.acm.org/communications/200811/?folio=40&CFID=33768312&CFTOKEN=64607598)

------
radu_floricica
It's also that AFAIK, it's the first major lisp in a while to be completely
redesigned without regard to compatibility with CL. There's a ton of stuff
that was just waiting to be done, but couldn't because people kept using car
and cdr instead of first and rest.

~~~
mahmud
No, Common Lisp has both sets of operators; it has car, cdr and all the
combinations of c(a|d)+r you can handle, it also has the ordinal number words,
first, second .. tenth, and rest.

The difference is that first, rest et al. are used when the data being handled
are _proper_ lists. A list of items terminated by nil.

Car, cdr and others can be used with lists as well, but they're more primitive
operations that mean _cons_ cells; a pair data structure that has two parts.
You can view a proper list as "a primitive pair data structure that has the
first item of the list as its first cell, and has its second items a pointer
to rest of the list" .. and construct the rest inductively.

You can't use first and rest to operate on associative lists, graph structures
cyclical or otherwise and a host of other data structures.

Some programmers decide to make their intent clear when operating on proper
lists, while others prefer to stick to car and cdr out of habit, nostalgia,
not-knowing better, street cred, or as a _cheap_ _way_ _to_ _advance_
_pointers_ with one compact operation.

CAR and CDR are less relevant now that people use CLOS, CL's Object System,
and to a lesser extent structures. Defstruct gives you the accessor FREE, it
constructs the accessor functions as classname-slotname for the reader and
(setf classname-slotname) for the update/write function. With CLOS you can
choose the name for it with an initialization argument (:initarg :accessor,
:reader, or :writer)

Please update your Common Lisp prejudice check-list.

