> The age and more importantly stasis is a fair cop
I don't see how threading makes "age" a valid argument. CL is a language defined by a specification. Implementations have provided threading APIs for a while now and library authors have written cross-implementation threading APIs. Without even mentioning threading in the specification it's trivial to write multi-threaded CL applications today and I think that's a strength.
In a similar fashion, C++ hadn't included a threading API until C++11 (iirc). Yet implementations provided it and library authors had filled the gap for years until a standard API was adopted into the core standard library.
If CL was a language defined by an implementation that hadn't been updated in 10 years I might agree with you.
As for syntax it's odd. Rich Hickey himself has advocated the use of syntax-literals for data-structures citing legibility as a primary concern. One familiar with CL's access to the reader and read-table would allow the programmer to implement reader macros for the same effect without losing compatibility with the rest of CL (and the standard implements a few: #() for vectors for example, '() for (QUOTE ...) etc). Either way preference of syntax is superfluous when you have programmatic access to your language's parser and yet Cljoure programmers unfamiliar with this concept advocate that syntax-literals are the way of the future and CL's lack of syntax for various constructs is a weakness. It's a non-issue.
I've written reader macros for various flavours of assemblers. It's quite versatile.
Age isn't a very good criticism. A good specification is meant to withstand the years. CL's has done a pretty good job at that.
wrt baggage though, I will concede that perhaps they specified too much in the filepath API. A conformant CL implementation today will have to support some very obscure filesystems... which can be daunting for prospective implementation developers.
There's a BIG difference in ecosystems if a system starts out with pervasive threading or doesn't. In a slightly different domain, I saw this back when I was doing NT programming in the '90s. From the start it provided threads and plenty of thread safe stuff (and plenty not, including the MCV++ Standard Template Library in 1997, although that was mostly of an initial botch of the port from the HP? code), and this made quite a difference compared to trying to write threaded programs for UNIX(TM).
If you're not going to limit yourself to copying paradigms like the Actor model I argue you're going to be in for a world of hurt, even as your ecosystem matures, because you'll almost certainly have non-thread safe stuff from the days when the community wasn't considering threading.
So all I'm saying in this argument is that Common Lisp is traversing this painful path, and will never be as optimal as it might be, because when it was cast into concrete in 1984 threads weren't part of it.
The Clojure argument for standard data structure syntax-literals, and strict limits on reader macros, is indeed legibility, defined as portability between humans. I think it's an issue, but one that I think we'll have to agree to disagree on. Although I don't see gaining CL compatibility as a goal, the foundations of the languages are too different (functional vs. multiparadigm including but not limited to functional).
I agree that age itself isn't a good criticism, I was pointing out how Common Lisp's extreme age has resulted in issues, and "age criticisms" could be interpreted that way.
This goes all the way back all the way to the very first late '50s LISP, e.g. while I personally like them, classic examples are Contents of the Address Register and Contents of the Decrement Register (car and cdr) of the vacuum tube IBM 704. More consequential are things like Lisp-2 vs. Lisp-1; maybe it's just a matter of taste and not having written enough macros in my career but I prefer the latter.
Hmmm, to sum up, one argument for Clojure is that we now known enough to create a more restrictive dialect and benefit from the good taste of Rick Hickey and now others who are helping to carry the language's torch. Callow youth though he might be, mrottenkolber is spot on when he says it's an opinionated language, and that'll certainly mean among other things that it'll not be to many experienced Lisper's taste (probably easier if you're a Schemer, though).
I harp on SMP programming because I find it, and the functional programming solutions to it, very interesting, not to mention it's just plain better for writing robust software. Closure seems to have done a good job using the latter to address the former, and gaining those other minor details guaranteed FP grants you.
Common Lisp implementations deal with threads since day zero. The non-threaded standard has not prevented dozens of implementations to provide threads. Common Lisp has man different full implementations.
Clojure is basically just one real implementation.
Clojure limiting the use of reader macros is just another example where somebody is telling me how I should use a language. It's basically as in Java. Common Lisp and Lisp in generally has favor a different root: give power to the user. Why stop there. Why not provide a fixed amount of macros and remove the user-written macro facility from the language.
IMHO Clojure's omission of reader macros is sensible: it prevents proliferation of custom syntax, which makes it harder for a human to read code and reason about reader behaviour. The Clojure reader also already has its own literal syntax for vectors and maps [] and {} (which eliminates the most common use cases for reader macros).
If you believe that standards are helpful, then surely one standard reader behaviour is a good thing?
Regular macros are a different issue: they allow creation of custom control structures that aren't possible with normal functions. That's a powerful and useful feature, as many Lisps have proved over the years.
So Clojure rejects the former (unnecessary syntax sugar, potential for confusion, dubious value of reader proliferation) and accepts the latter (additional semantic power, proven utility). I personally think that's a good trade-off. YMMV of course.
Of course, there's nothing stopping you from implementing a custom reader in Clojure if you really want reader macros. So far, nobody (to my knowledge) seems to have cared enough to do this.
NOTE: I'm not bashing Common Lisp: just pointing out that language design has real trade-offs. For me, Clojure gets the majority of these design decisions right. For others, maybe reader macros are an essential feature and Clojure therefore doesn't work. No problem, use whatever works for you.
The reader is first of all there to extend s-expression syntax to new datatypes - not for arbitrary syntax.
Btw., vectors are written as #(1 2 3) in Common Lisp.
Thus if I as a developer want to serialize my data structure to an s-expression, I can use reader macros.
New data type syntaxes does not make code much harder to read.
> If you believe that standards are helpful, then surely one standard reader behaviour is a good thing?
Sure, Common Lisp has a standard reader. An extensible one.
> Regular macros are a different issue: they allow creation of custom control structures that aren't possible with normal functions. That's a powerful and useful feature, as many Lisps have proved over the years.
Custom control structures don't make the code harder to understand? Strange.
> For me, Clojure gets the majority of these design decisions right.
For me many of these Clojure design decisions look arbitrary and some I find just wrong. But that's just me.
"Common Lisp implementations deal with threads since day zero."
Really?
Name them.
Granted, I'm not sure myself, since I left the community in the fall of 1984 when I left Goldhill (which ran on 16 bit x86 and 640KiB - minus what DOS extra took up, so not only did it not do threading, it didn't even (initially, while I was there) do lexical scoping (!)). But I heard it took some time for Symbolics to adopt Common Lisp (installed base problem), and I don't know about the other early commercial ones.
Allegro Common Lisp is rather early to have had threading on the PC platform. Did the Macintosh do threading as of 1987? What about Lucid? A quick look at the indexes of the users guides for Liquid Common Lisp, which I understand to be its current version, don't have the word thread in them.
So, you base your knowledge of Common Lisp on the fall of 1984, the same year the book Common Lisp the Language was published? Strange. What happened in the meantime? Did they just wake you up?
Liquid Common Lisp? The chapter on 'multitasking' is hard to find?
Threads are in Common Lisp usually called Processes. The Lisp Machine had them and basically the same API was used in Common Lisp implementations. Allegro CL, Lucid, LispWorks, ...
The entry points have been literally for decades functions like PROCESS-RUN-FUNCTION and MAKE-PROCESS.
> Did the Macintosh do threading as of 1987?
The Macintosh OS at that time did cooperative multitasking. It was supported by Macintosh Common Lisp. Macintosh Common Lisp supported what was possible and the old Mac OS was crippled.
Symbolics had little problem providing Common Lisp. The Symbolics Lisp Machine ran Common Lisp and ZetaLisp side by side in one Lisp. Of course you could call the scheduler functionality from within Common Lisp. Since Symbolics also developed a new scheduler, I guess the new one was written Common Lisp.
Yes, because I'd forgotten that the Lisp Machine used the word process for threads.
My knowledge is pretty much limited to the free Common Lisp implementations, since I never had a budget for a commercial one, and their threading story has not been so happy. But that's not a valid criticism of Common Lisp.
And yet it's trivial to write a highly multithreaded application with STM in most CL implementations today.
If Clojure was less inclined to differentiate itself from other Lisps and co-opting the future of the language I believe there'd be far less zealotry on both sides of the fence. IMO Clojure is just fine. I don't see the reason why it needs to persist CL FUD in order to make its case. They're both very practical implementations of Lisp after all.
FWIW, I've been in the Clojure community for a few years and see almost zero FUD about Common Lisp. The atmosphere in the Clojure community is much more about pragmatism than zealotry.
Mostly, I see a healthy respect for other Lisps and a recognition that learning from traditions is a good way to build good things for the future.
Being in the Clojure myself, I'd say the aforementioned "healthy respect" and "pragmatism" come from the fact that we all probably have migrated through at least a few languages before ending up at Clojure, which gives us a sense of perspective that keeps most of the zeal away.
I don't see how threading makes "age" a valid argument. CL is a language defined by a specification. Implementations have provided threading APIs for a while now and library authors have written cross-implementation threading APIs. Without even mentioning threading in the specification it's trivial to write multi-threaded CL applications today and I think that's a strength.
In a similar fashion, C++ hadn't included a threading API until C++11 (iirc). Yet implementations provided it and library authors had filled the gap for years until a standard API was adopted into the core standard library.
If CL was a language defined by an implementation that hadn't been updated in 10 years I might agree with you.
As for syntax it's odd. Rich Hickey himself has advocated the use of syntax-literals for data-structures citing legibility as a primary concern. One familiar with CL's access to the reader and read-table would allow the programmer to implement reader macros for the same effect without losing compatibility with the rest of CL (and the standard implements a few: #() for vectors for example, '() for (QUOTE ...) etc). Either way preference of syntax is superfluous when you have programmatic access to your language's parser and yet Cljoure programmers unfamiliar with this concept advocate that syntax-literals are the way of the future and CL's lack of syntax for various constructs is a weakness. It's a non-issue.
I've written reader macros for various flavours of assemblers. It's quite versatile.
Age isn't a very good criticism. A good specification is meant to withstand the years. CL's has done a pretty good job at that.
wrt baggage though, I will concede that perhaps they specified too much in the filepath API. A conformant CL implementation today will have to support some very obscure filesystems... which can be daunting for prospective implementation developers.