Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@vindarel
Last active April 17, 2024 22:01
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vindarel/3484a4bcc944a5be143e74bfae1025e4 to your computer and use it in GitHub Desktop.
Save vindarel/3484a4bcc944a5be143e74bfae1025e4 to your computer and use it in GitHub Desktop.
Notes on Common Lisp VS Clojure

Testimonies

CL's compiler

The thing in CL I miss most doing Clojure as my day job? CL's compiler. I like having a compiler tell me at compile time about the mistakes I've made. Bogus arguments. Unreachable code because of unhandled exceptions, and so on. CL saves me round after round of bugs that in clojure aren't found until you run the code. If you test well, it's found when testing, if you don't it's found in production. "Clojure compiler" almost demands air quotes.

CL's optional but oh-so-useful model of type declarations is also infinitely more useful (to me) than Clojure's use of "spec", and instrumentation that happens only at test time because of the cost. Depending on the OPTIMIZE declarations, other type defs are a floor wax and dessert topping. Want checks for argument types? Lower optimizations. Want most efficient machine code? High optimizations.

/u/Decweb, March 2023 https://www.reddit.com/r/lisp/comments/11ttnxk/the_rise_fall_of_lisp_too_good_for_the_rest_of/jczpysp/

Interactive development

I have semi-frequent occasion to work in Clojure, but Clojure lacks some features of Common Lisp that I consider important. The most important of these is that Common Lisp, like Smalltalk, but unlike most other languages, including Clojure, is designed from the ground up to support developing a program interactively while it runs. I want to see if I can have Clojure for those cases where it's the right tool, without losing the programming-as-teaching features of Common Lisp that I miss when working in other languages.

I know someone is probably going to object that Clojure, too, is designed to support interactive development; my answer is: no, it isn't. Not in the sense I'm talking about.

As an example of what I mean, consider the standard Common Lisp generic function UPDATE-INSTANCE-FOR-REDEFINED-CLASS. This function is part of a standard protocol in Common Lisp that enables your program to automatically update existing instances of previously-defined classes to properly conform to a changed class definition.

As I've observed elsewhere, the existence of this standard function is not an accident or an eccentricity, even though it makes no sense in most languages. It makes sense in the context of Common Lisp because the normal mode of development is for your work in progress to be running while you work on it, and no experienced Lisper would expect to have to restart the program or reload code just because they redefined a class. The designers of Common Lisp made this protocol a part of the language standard because they took for granted that the normal way to work on a program was to alter its definitions while it ran, and took for granted that you should reasonably expect the program to continue to work properly while you were doing that.

In other words, the language is designed from the ground up to support interactive programming. Smalltalk is designed with a similar set of assumptions. Most other languages, not so much.

https://www.reddit.com/r/lisp/comments/e1jr8b/cloture_clojure_in_common_lisp/f8ql96b/

"the tooling for most CL implementations is just plain light years ahead of Clojure"

For Clojure the interactive debugging experience is just plain dreadful and for a dynamic language this is pants on head crazy imo. For me a dynamic language has to have a good interactive debugging experience because you have foregone the support of a static compilation and instead wish to reason about your program at runtime. But with the JVM stack traces and lack of interactive debugger Clojure just does not support you in this regard. And as a side note the lack of an identity print is annoying as well e.g. (+ (print 4) (print 4)) "4" "4" 8 (yes, it's easy to add...)

Clojure's decision to use persistent data structures is good but it's really the only standout thing for me other than some syntax sugar like hash maps.

from https://news.ycombinator.com/item?id=13981261 (2017)

A question about it:

I have been led to believe that Clojure can also do interactive development. Certainly, with Figwheel it is possible to do interactive development. But with Clojure, I'm not so sure. What is the story please?

mikelevins:

It's certainly possible to develop interactively with Clojure. If you're used to Common Lisp, the environment will feel clumsy and incomplete. If you're used to figwheel, you'll miss some of the nice reloading and debugging conveniences, but interactive development with vanilla Clojure is certainly possible, and indeed good enough that some people like it (and some might take offense at my lukewarm praise).

Neither Clojure nor ClojureScript is in the same league as traditional Lisp and Smalltalk environments, but if you're not already used to those, you won't miss them. If you want to develop interactively and you want to use Clojure, you can certainly do it.

https://www.reddit.com/r/lisp/comments/q6pou3/notes_on_common_lisp_vs_clojure/


On debugging and performance:

I use Clojure at work but wow do I miss just about everything about Common Lisp whenever I have to debug anything or want performant code. Being able to be in nested errors and click at any part of the stack to inspect lexical bindings is extremely useful, and more importantly, clicking on an object then pushing M- to copy it to my REPL is much nicer than what Clojure offers (tap>, which I consider a glorified pretty printer even if you use tools like Portal).

As for performance, well, Common Lisp lets you statically type things, and SBCL can emit really efficient code if you do this. I find it helpful to run DISASSEMBLE on my own code to see what exactly is being emitted and optimize from there. And more importantly, packages like SB-SIMD and Loopus are a god send for any number crunching application.

from koito17, https://news.ycombinator.com/item?id=36887792, 2023.

or

As a Clojure dev, break loops and REPL-driven workflows sound wonderful, and something we could definitely benefit from, which would make it more like front-end coding with JS/TypeScript using the browser’s awesome debugging tools. Sadly, the state of tooling and community support for the Clojure ecosystem seems to be pretty lackluster at present.

from temporallobe, same HN thread

After looking at the quite old benchmarks, ABCL seems to perform alright. Can anyone share their experience with ABCL in terms of performance, stability and memory usage?

I wish I could give you more concrete numbers with an application you could test and see for yourself. Since I can’t do that, I will tell you about my recent work with ABCL. I ported a small Clojure server-side utility to ABCL and can qualitatively tell you that the performance was close to Clojure. After profiling the ABCL version, I believe I can attribute the differences to ABCL’s use of Java reflection for its Java FFI.

I’ve already been successfully deploying Clojure-based applications professionally, and as I’ve gotten more into Common Lisp, I’d like to start deploying Common Lisp based applications as well. I recently posted a patch to the ABCL mailing list and got a very quick response from the maintainer. I really like the quality of the ABCL code base. The compiler itself was very approachable and easy to understand.

I think ABCL really is a worthwhile target in the Common Lisp world because:

  • Painless Java FFI. You avoid all the instability and signaling issues that crop up when using the JVM combined with SBCL or CCL. If you make a lot of calls, native Java is always going to be faster anyhow than calls over JNI (which is more comparable to reflection).
  • Use large heaps without worry. Part of the benefit of the JVM is its proven ability to have huge heaps (I’ve been part of projects that had 64GB+ heaps (though honestly I’d rather stay small)).
  • JVM platform is well supported and tested on a number of OS and hardware platforms

SBCL uses conservative garbage collection and I’m curious how well it would handle really large heaps. CCL uses precise garbage collection but again, I’d like to know how it handles really large heaps. In general, I want all my applications to run with heaps that are naturally in CCL’s or SBCL’s sweet spot, but I’d love to know I could use ABCL if I really ever needed huge heaps. I’m really getting into Common Lisp because I really like the implementation choices. Having a solid Java FFI unfortunately is usually a requirement in my workplace.

To me, ABCL will be /better/ than using Clojure if ABCL’s Java FFI moves away from reflection (when possible). This will close any performance gap with Clojure for most applications. I think this can be done relatively easily in the current ABCL implementation, and I have an idea of how to do it but unfortunately have had no time lately to devote to it. The reason I say “better than Clojure” is that I can write applications that target both ABCL and SBCL/CCL – I can abstract away my Java APIs if I really have to have them (or use LispWorks with a solid Java FFI if I don’t need a ton of Java interoperability). Then when I need fast startup time or low memory footprint, I can use these other CL implementations which are much better suited to it.

The main benefit where I still see Clojure having an edge is if you need a heavy JS-based web interface. I’m not a JS developer, but I was able to successfully use Clojurescript and make a nice looking web application that had pretty seamless interoperability with my Clojure-based server.

Anyhow, I hope this helps you. ABCL is great, I have been very impressed with it and I encourage you to try it out.

from https://www.reddit.com/r/lisp/comments/d48gcr/how_well_does_abcl_perform/

Thoughts on learning Clojure and Common Lisp in 2019 (and some other stuff)

Clojure: It’s a really cool language with a stable core — but there are some issues that make it difficult to get into and sometimes it feels hard to do what you want to do and slower than you would want it to be.

Common Lisp: CL is very fun to program with. It’s very stable and mature ecosystem. If you use sbcl + portacle getting started is basically 5 minutes. I definitely recommend common lisp as an entry point to lisp.

https://medium.com/@yvanscher/what-have-i-been-up-to-for-the-last-few-months-of-2019-5997b632876b

Clojure annoyances (2016): memory hog, slow startup, deal with Java, awful backtraces, not always expressive, heavy setup, docstrings require an extra line

Every time this is brought up there are arguments that Clojure and the JVM alone don’t use too much memory. But once lein is starting an nREPL for a non-trivial project, you’ll want to have a 16+ GB machine. The situation would be even worse if you use a heavy IDE (like IntelliJ or Eclipse). […] So if you’re not careful, you’ll want to limit yourself to running one project at a time.

Clojure starts up quickly (relative to lein, anyway). But the full lein environment is taking me 17+ seconds in a default Luminus project.

http://www.micahelliott.com/posts/2016-12-03-clojure-annoyances.html

When should I choose Common Lisp over Clojure for business (or vice-versa)? (2022)

"If you expect to integrate with others' libraries, such as deliver a project to a customer - Clojure might be more pragmatic since it runs on JVM..." (answer:) "SBCL, ECL, LispWorks, and Allegro all allow delivering a shared library, so your Lisp code can roughly look like a C API to the outside world. (It's not 100% straightforward, but it definitely works.)"


"Have you found it difficult to find freelancers/full-time employees?" "No issues finding freelancers, just go to #lisp on IRC. Local full time employees will depend on where you are based. You can always train those with no CL experience. At one time I trained 6 interns at once to code in lisp in a couple of months."


"Common Lisp is really, really good if you know how to program it quite well, and aren't too distracted by deep philosophical thoughts about the nature of programming that Lisp sometimes has a reputation for providing.

For hiring other programmers, you should be ready to train them and review their code. A good programmer will pick up Lisp and be very productive with it in less than a month.

Except for a small select few things, Lisp code almost never breaks. The ecosystem, while imperfect, is extremely stable. Use Common Lisp if that's valuable to you.

Lisp is also good at letting you develop extremely chiseled applications, ones that need to be fast, flexible, and no-nonsense. Deployment isn't hard, but it's also quite barebones and you'll have to use some elbow grease to get a good deployment setup.

On the other hand, if you're going to be doing a zillion integrations with other software and services, having Java at your disposal, while incredibly boring, might be a lot more advantageous. I don't personally recommend Common Lisp for "just" gluing things together; I recommend it when you and/or a team you hire really need to roll up your sleeves and program something."

https://www.reddit.com/r/lisp/comments/wn7qhr/when_should_i_choose_common_lisp_over_clojure_for/


See also:

Libraries:

  • clj-con implements Clojure concurrency primitives in CL.
  • Cloture wants to be Clojure in Common Lisp. Work in progress.
@swapneils
Copy link

Thanks for collating this! I'm trying to learn both languages, and these kinds of analyses are very useful for determining how much to prioritize each given my personal preferences.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment