News for hackers. Stuff that matters.
Re:[Ask HN]: Clojure - why the optimism? by hga on Sunday January 24, 2010 @12:13PM (#1073481)
"If other lisps never made it into mainstream, why would Clojure all the sudden nail it?"

Very good question; here are my guesses:

We are exiting a Dark Age when the use of non-mainstream languages was nearly impossible (I suspect this has to do with the dot com bust: companies just don't have the money they used to have to throw at "safe" mainstream choices).

I strongly suspect PG's success story and thorough explanations of why Lisp wins made more people willing to give Lisps a chance.

The more varied syntax (e.g. heavy and appropriate use of vectors which are denoted by square brackets) finds favor with a lot of people who think LISP stands for Lots of Irritating Sets of Parenthesis.

The multi-thread/multi-core "future" is here today and many have come to the conclusion that functional programming seems to be the best approach we can see today (there's been a lot of research into this since the '80s or earlier, nothing else has really stuck to the wall; note that Microsoft's F# dialect of OCaml is perhaps the first "mainstream" functional language). Lisps have always had a good story there as the first widely used functional language (well, technically most of them are multiparadigm but strongly functional), with a strong mathematical basis (the lambda calculus). Clojure takes full advantage of this.

Apropos of the above, Haskell, the ML family and maybe Erlang were probably the only more popular strongly functional languages prior to Clojure, but for many they are harder to master; Lisps are more straightforward, they are dynamically typed, etc.

Basing it on the JVM makes a big difference: for some it provides a warm and fuzzy since Java is so widely accepted and the Java/JVM ecosystem is so big and healthy. For many this provides an easier path to getting started, and if you want to get real world stuff done quickly, there's all those Java libraries and packages that can easily be directly called from Clojure and that can call Clojure.

(Actually, running on the JVM makes it easy for pretty much everyone to get started on most any platform, just download the .jar file and run it in the JVM that most likely is already installed on your system.)

Rich Hickey has made a lot of good choices in designing the language and its core libraries; it "feels" like a good fusion of Scheme and Common Lisp, richer than the former and not at all crufty or impossibly massive like the latter.

The community is very functional, so to speak ^_^. There's one Google Group where most of the action happens, it's very friendly and helpful and nasty people are not tolerated on it.

Re:[Ask HN]: Clojure - why the optimism? by morphir on Sunday January 24, 2010 @12:56PM (#1073553)
Many good points here.

Rich Hickey has made a lot of good choices in designing the language and its core libraries; it "feels" like a good fusion of Scheme and Common Lisp, richer than the former and not at all crufty or impossibly massive like the latter.

Could you give some language design examples that differs clojure from other lisps?

I heard someone speak about 'data' is separated from 'code' in clojure.. any examples of this?

Re:[Ask HN]: Clojure - why the optimism? by hga on Sunday January 24, 2010 @03:04PM (#1073712)
(Note: I don't know much about EMACS Lisp, but obviously it's mostly for use in EMACS and unlike all modern Lisps it's dynamically scoped, an early error in the Lisp family that Scheme started to fix and that was the biggest change in Common Lisp from its non-Scheme ancestors.)

The biggest is that Clojure is what I call "strongly functional": it's not a pure functional language like Haskell (where you e.g. do IO in monads, which call pure functional code) but e.g. its data structures are immutable. With that foundation, made practical with its solution to the trivial update problem, much can be done.

Hmmm, for that matter, the Scheme and Common Lisp standards don't address concurrency at all (Common Lisp is frozen in amber and Scheme hasn't gotten to it yet). There are many implementations for this, of course, and maybe even some de facto community standardization for Common Lisp (can't remember the details, I moved fully to Scheme in 1984 and am in the process of moving to Clojure now), but this is not the sort of thing you can address with a library like networking (with the exception call/cc games with Scheme as I recall).

Scheme and Clojure are Lisp-1s, variables have one value, which might be a function. For backwards compatibility Common Lisp is a Lisp-2, variables have value values and function values, which gets used depends on the context.

At its base I'd say Clojure is higher level than Scheme (which pretty much only has a base) and Common Lisp. E.g. in either you can easily do lazy evaluation, in Clojure it's heavily used in the sequence library.

A very big thing is Clojure's collections. Common Lisp and Scheme are LISPs, LISt Processing languages where the list is the alpha and omega and things like vectors (one dimensional arrays) feel tacked on. Clojure provides a unified collection abstraction with a variety of concrete realizations. The most important ones are lists, vectors, maps (key value pairs) and sets (collections of unique values), and the first three are first class citizens in terms of syntax ( (), [], {} ).

The biggest thing that will hit a Lisp veteran is how collections other than lists are used in the special forms (syntax). A bunch of them intelligently substitute vectors where only lists were used in previous Lisps. E.g. fn is the Scheme equivalent of lambda and the parameter list is a vector. E.g. the following return a function that adds two numbers:

  (lambda (x y)
    (+ x y))

  (fn [x y]
    (+ x y))
There's a fair set of things that are fallout from it being built on top of the JVM (note, it started out with JVM and CLR support, the latter was dropped to speed development of the language per se and has been revived independently). E.g. for security reasons the JVM doesn't offer native tail call optimization (this will hopefully be fixed in the next version), so there are a variety of hacks to achieve the same result, most notably the recur special form.

Many people like this: if you accidentally put/move a recur to a non-tail call position, you get a clear error instead of blowing your stack or running slowly.

There are nil/null/true/false details that are partly driven by the JVM and partly due to the emphasis on functional programming.

A concise overview can be found at http://clojure.org/lisps.

As for "'data' [being] separated from 'code'" ... I'm not sure what he meant. Code is more than lists now, but it's still homoiconic (http://en.wikipedia.org/wiki/Homoiconicity), it's all readable, the function read groks vectors ( {} ) and maps ( {} ) just fine.