Skip to content

Instantly share code, notes, and snippets.

@vindarel
Last active April 20, 2024 03:18
Show Gist options
  • Star 114 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save vindarel/c1ef5e043773921e3b11d8f4fe1ca7ac to your computer and use it in GitHub Desktop.
Save vindarel/c1ef5e043773921e3b11d8f4fe1ca7ac to your computer and use it in GitHub Desktop.
Common Lisp VS Racket. Feedback from (common) lispers.

Developer experience, libraries, performance… (2021/11)

I'll preface this with three things. 1. I prefer schemes over Common Lisps, and I prefer Racket of the Schemes. 2. There is more to it than the points I raise here. 3. I assume you have no previous experience with Lisp, and don't have a preference for Schemes over Common Lisp. With all that out of the way... I would say Common Lisp/SBCL. Let me explain

  1. SBCL Is by far the most common of the CL implementations in 2021. It will be the easiest to find help for, easiest to find videos about, and many major open source CL projects are written using SBCL
  2. Download a binary directly from the website http://www.sbcl.org/platform-table.html (even for M1 macs) to get up and running (easy to get started)
  3. Great video for setting up Emacs + Slime + Quick Lisp https://www.youtube.com/watch?v=VnWVu8VVDbI

Now as to why Common Lisp over Scheme

  1. A better developer experience. Emacs + Slime is way better development and debugging experience than either Emacs + Geiser, or Emacs + Racket-Mode or Drracket.
  2. There are tons more libraries implementing hard things you don't want to reinvent yourself written in CL. (I run into this problem with Racket all the time)
  3. The Performance of CL is much better than Scheme. One example is here https://github.com/luizsol/PrimesResult. Lisp is 11, Chez scheme implementation is 40
  4. Great books that deal with solving practical programming problems

I could go on, but I'll stop there. Now if you still want to use Scheme, Racket blows the other Schemes out of the water with what you get out of the box. […] But it is not without its problems.

https://www.reddit.com/r/lisp/comments/qlcza4/best_lisp_dialect/hj22i7n/

"horrible" interactive experience (2021/11)

Except that Racket has horrible interactive development experience: authoritarian module system that prevents modification to the system, no condition/restart but just print you a trace, and little runtime inspector/debugger support (and it's probably impossible to add because modifying stack at runtime seems contradictory with its ideology). I find it unusable.

Scheme itself is a nice language, and I find MIT/Scheme much more comfortable to use (for a traditional Lisper) overall, because of its inspectability, modifiability and a condition/restart system. And it has real first-class environment!

https://www.reddit.com/r/lisp/comments/qlcza4/best_lisp_dialect/hj2kufx/


Racket is a nice language with the batteries included and lots of polish aimed at attracting new developers. However, Common Lisp really is a superior language in almost every way. As mentioned, I am having mixed thoughts. I have been using Racket sparingly to get my feet wet for the past few months, and while it is nice, there is a lot to be missed from Common Lisp

Deficiencies of Racket (compared to CL):

  • No built-in multi-methods and lots of super-specialized functions (the same functions but for lists, vectors, hashmaps etc; to be fair CL is not ideal here either).
  • No introspection compared to one with SLIME.
  • Debugger... well, essentially absent if you have to compare with CL
  • Module re-loading removes everything in running image (in DrRacket, perhaps, you can do a bit better in Geiser).
  • Efficiency: compare the speed of SBCL and Racket
  • Support for OOP: nothing compared to CLOS. Racket has message passing style OOP, which is OK (Smalltalk does it too, for example), but the syntax is so verbose. And again, lack of introspection makes it impossible to work with.
  • Libraries: compared even to CL libraries maintained by enthusiasts, most of Racket libraries are half-baked: unfinished, failing to build, and lacking documentation (and at least in CL you have DOCUMENTATION, DESCRIBE and APROPOS + introspection and good debugger to figure out what the library functions are doing).

This list is not to degrade Racket completely, but just to point out that the transition CL -> Racket is not changing for something better as there is a lot to like about Scheme-like languages, but rather a trade off.

Also, regarding the library ecosystem, Racket also suffered from all of the same issues that plagued Common Lisp. A quick glance at Racket package's index will show that many libraries/packages also fit the author's description of a library "developed by a single person and then stopped being maintained shortly thereafter".

Even worse is that in many cases, the library ecosystem situation in Racket is even worse than Common Lisp because many Racket libraries, even critical one like, for example, DBI library, have negative bus factor, i.e multiple Racket libraries are developed and maintained by a single developer. This also affects the quality of many Racket libraries, and many of them are very immature (or even feature incomplete), especially when compared against the many battle-tested libraries that Common Lisp has (and we haven't even mention performance here). For example, I doubt Racket's web server can compare against Common Lisp's Hunchentoot.

https://www.reddit.com/r/lisp/comments/6w44ay/moving_away_from_common_lisp_kind_of/

Racket does have one advantage that I know of: It has a GUI library that is portable across Windows, macOS, and Linux, without needing to run X11 on non-Linux platforms. To get that with CL, you'll have to buy LispWorks.

Other than that, Racket isn't as dynamic as Common Lisp. You'll use the same programming methodology you're already familiar with using Java/Kotlin. Racket's notion of OOP is inspired by Java, and so are its modules, and the "raco" command-line build tool. You can't change anything in a Racket program after compile time.

Others have already talked about some of the benefits of Common Lisp. A couple of things I can add are:

  • CL programs can be modified while the program is running, which speeds up debugging because you can often fix the bug and then resume the program from the stack frame above the one that raised a condition, instead of having to run the program from the beginning. Only Smalltalk has a similar capability.
  • The CLOS object oriented programming system is extremely powerful, and nothing like it exists in any other language.

You’ll miss out on Common Lisp’s condition system approach to handling errors which is fairly unique.

https://www.reddit.com/r/lisp/comments/ijubzr/am_i_missing_out_on_something_if_i_learn_lisp_via/

Racket's interactivity << Guile << Common Lisp

Racket is basically lisp syntax but Haskell interactivity. REPL is basically just a debug tool, and during developing a project I need to restart Racket process and reload all modules frequently. With Common Lisp I have a CL process live through the whole development process. By default you can't reload a module (there's way to do it, but afaik nobody use it in source file). The module system is "hygienic", which means you can't modify everything if you want. Basically no interactive debugger, and you only get a backtrace printed (recall Haskell's trace huh?).

In practice I've found that there are 2 "languages" actually in use on the Racket platform: Racket itself, and Scribble (which is used to generate the documentation). Any other language you'll find out there is pretty much a toy.

It comes down to the fact that the process of actually making a new language in Racket is under-documented and difficult, and this is speaking as someone who's actually done it. The dream of Racket is to have a DSL for every domain (like you said) but the reality is that everyone just writes regular Racket and it functions as a souped-up Scheme. And in the realm of just regular ol' lisps, Racket is beaten by Clojure and CL due to their far-better support for REPL-based development and better tools (Emacs + SLIME or Emacs + CIDER is miles and miles better than the clunky toy that is DrRacket). That's my two cents, and I actually like Racket but it feels like sort of an unfulfilled promise, which is why I can't really recommend it in earnest.

https://www.reddit.com/r/lisp/comments/igci3l/racket_seems_op/g2ulpab/

SLIME is a fantastic tool and Quicklisp is such a great way to get libraries; it’s effortless. I’m more of a schemer myself and I wish we had the same level of tooling. That would truly make Scheme a fantastic way to develop stuff. Geiser just doesn’t do interactive development as well as SLIME.

https://lobste.rs/s/whsc7o/running_lisp_production (2021, 06)


Racket is full of restrictions, and when I used it I ran into those restrictions constantly.

  • Racket's developers sacrificed interactive programming to get stronger static guarantees. This is one of the things that annoys me the most about Racket. Programming in it feels like programming in Java.
  • Being more specific, in Racket, top module-level definitions are immutable. You can't redefine functions or change anything created with define at the top level of a file.
  • Modules can't be inspected or reloaded at runtime. If you need to change something in a module, you have to save the change to disk, restart Racket, and reload your program.
  • The "phase level" system restricts which functions you can call from procedural macros (not that normal list utilities are useful in macros, since macros do not operate on lists).
  • Like Scheme, Racket has continuations. Unlike Scheme, Racket has "continuation barriers" that can be used to restrict the use of continuations.
  • Racket's macro hygiene creates surprising failure modes, particularly if you write macros that treat certain symbols specially.
  • Racket's object system allows superclasses to restrict how subclasses can extend them.
  • There's no such thing as apropos, describe, or documentation. If you want to know what Racket defines, you are expected to use static sources of information, such as the source code or the Web docs.
  • Racket used to have something like Quicklisp, but they abandoned it in favor of something like Python's pip tool.

https://www.reddit.com/r/lisp/comments/obk7x2/how_is_racket_more_opinionated_than_cl/ (2021, 07)

Typed Racket VS Coalton

Coalton is pretty recent (first released in sept, 2021). A comparison by one of its author:

Take this with a grain of salt, because I’m neither a user nor expert of Typed Racket, but:

  1. Typed Racket focusses more on the gradual typing of a given program. It has lots of features to make that easier, such as occurrence typing. Coalton is a separate, embedded language.
  2. Typed Racket achieves polymorphism through subtyping and and first-order type variables. Coalton achieves polymorphism through type variables, higher-kinded types, and type classes.
  3. Coalton, like ML and Haskell, focuses on defining objects by their properties and supported functions. This is a proposed way of having modular, reusable code. Typed Racket, as far as I can tell, has no such features.
  4. Coalton code can be fully inferred, so type annotations are not necessary. Typed Racket cannot.

All in all, I think the biggest and most important take-away is that Typed Racket goes through great effort to seamlessly blend with ordinary Racket. But that means Typed Racket has to compromise on type system features that can only be supported if you’re willing to change the language itself.

Coalton puts the type system first, opting for something close to Haskell, at the expense of not being a system for gradually typing Common Lisp, and instead being a separate language altogether.

stylewarning on https://www.reddit.com/r/lisp/comments/plpy13/introducing_coalton_how_to_have_our_typed_cake/


Discussed on:

See also:

@shenlebantongying
Copy link

Good read. Glad to see more updates.

@nery90
Copy link

nery90 commented Jan 17, 2022

Thanks for this. Very enlightening and useful, specially to somebody that is willing to start diving into the Lisp world.

@em7
Copy link

em7 commented Jun 3, 2022

Since this is no Zuck's social network, there's no like button. So a comment: Thank you, it was a good reading.

@behnamoh
Copy link

behnamoh commented Sep 5, 2022

Since this is no Zuck's social network, there's no like button. So a comment: Thank you, it was a good reading.

there’s literally a star button tho…

@shenlebantongying
Copy link

shenlebantongying commented Sep 5, 2022

Those two languages are designed with different goals in mind. Rather than trying to prove one is stronger than another, comparing why a language is designed to serve its users yield more meaningful words.

e.g. DrRacker doesn't have a REPL like lisp. It is a deliberate choice made after the observation that REPL causes confusion in education.

@bauripalash
Copy link

I tried racket while I was getting into the lisp world.
After few days of tinkering, I felt Racket is good but is not suitable for me. Error messages are really unhelpful. Finding a solution for some problem is really hard, I guess that's applicable to every newer language. Plus, I read few months ago somewhere that, Beautiful Racket's developer left the racket community due to some folks insulted and acted very rudely to him. BR in my opinion was the only "good" resources around the web for racket newbies.

@hav-gerdint
Copy link

Clojure?

@vindarel
Copy link
Author

vindarel commented Sep 6, 2022

Clojure?

I don't use Clojure myself: everytime I try I am scared away by the memory it is needed to start a (web) project, the long startup time and the inability to install a dependency from the REPL (at least by default). Everything is so smooth in CL. But I take notes on Common Lisp VS Clojure too if that's what you need ;) https://gist.github.com/vindarel/3484a4bcc944a5be143e74bfae1025e4

@cheeze2000
Copy link

thank you for this, and now i shall try common lisp

@j0el
Copy link

j0el commented Sep 10, 2022

Lisp was the first language I learned in college way back in the 60's, but have not used it very much since then except for simple emacs stuff. I would like to give it a go again and will try SBCL. Any recommendations for a tutorial on setting up a decent environment/worklflow?

@vindarel
Copy link
Author

@j0el Sure. To understand and install the building blocks, see the Cookbook/getting-started. You essentially only need a Lisp implementation (SBCL) and Quicklisp. You can start writing Lisp code in a file and load it in the default SBCL REPL, and whenever you want you setup an editor. For Emacs you need Slime. See Doom Emacs' layer, Portacle and emacs4cl for vanilla Emacs. Also the Cookbook/Emacs. You can try out CL in Vim, Atom, Sublime, VScode (good to very-good support), Jupyter notebooks and also Lem (an Emacs-like editor written in CL). The free LispWorks version has a good GUI.

Once you are ready, create your first project, then look at my project skeleton: https://www.youtube.com/watch?v=XFc513MJjos (https://github.com/vindarel/cl-cookieproject).

@j0el
Copy link

j0el commented Sep 15, 2022 via email

@redbar0n
Copy link

redbar0n commented Oct 24, 2022

CL vs. Arc (by Paul Graham)?

@vindarel
Copy link
Author

CL vs. Arc (by Paul Graham)?

@redbar0n No need for this^^ Arc is a toy with one deployed web app, but if you like the syntax (I could see why), you can have it in CL!

@redbar0n
Copy link

Ok. Arc is written in Racket, I see.

What about CL vs. Qi (a functional, flow oriented DSL also written in Racket)?

@vindarel
Copy link
Author

What about CL vs. Qi (a functional, flow oriented DSL also written in Racket)?

That would be a CL library VS Qi. I know of threading macros for CL (arrow-macros), but not one similar to Qi. With lambda shorthands we can have argument placeholders, with lparallel we can have parallel equivalents of or, and, sort, map… At first glance Qi's switch makes me think of pattern matching (then, Trivia in CL). Still, not one similar library I know of. There probably is one!

@massimo-zaniboni
Copy link

This part of a comment from Reddit is not 100% fair.

In practice I've found that there are 2 "languages" actually in use on the Racket platform: Racket itself, and Scribble (which is used to generate the documentation). Any other language you'll find out there is pretty much a toy.

I used Typed-Racket, Nanopass and EBNF and they were working in a good way and they do not seem toys. Typed-Racket is very well designed. Nanopass is one of the best DSL for writing compilers, and the only drawback were some obscure error messages. I read that the video of Racket conferences are edited using a video editing DSL language. There is a book about Language Oriented Programming (LOP) in Racket https://serverracket.com/anthropology/ , collecting the experience of many creators of Racket DSL languages.

Other examples of very professional and used DSL: Redex (for sure) and probably Rosette.

It comes down to the fact that the process of actually making a new language in Racket is under-documented and difficult, and this is speaking as someone who's actually done it.

I'm only a consumer of DSL and not a creator. So probably this is true. In any case, for this complex tasks it is normal that it is more difficult creating a new DSL rather than using it.

The dream of Racket is to have a DSL for every domain (like you said) but the reality is that everyone just writes regular Racket and it functions as a souped-up Scheme.

I think that this is not fair. LOP in Racket is definitely a thing and there are no many better alternatives for LOP programming out there.

BTW, I prefer CL because it is more interactive and funny, but for LOP, Racket has these advantages:

  • macro expansion of DSL code maintains tracks of the original source code location, so error messages are less cryptic
  • Racket has a good-enough GUI environment (not very professional in the look and feel, but complete and powerful) that is standard, so DSL with GUI tools (like Redex) can use it
  • one can add documentation using the Racket-way, that is very professional and consistent
  • if someone create a good DSL, in Racket there is a more uniform community, because everything starts from the main Racket web-site, and it is easier to be noticed, becoming a "standard" and used DSL

I prefer CL. CL wins for the interactive experience, and many other aspects. But for LOP, Racket has many good idea and implementations from which CL can benefit, if they are ported to it.

@port19x
Copy link

port19x commented Dec 26, 2023

I found the top answer of the following stack overflow post very informative: https://stackoverflow.com/questions/5368090/what-are-the-actual-differences-between-scheme-and-common-lisp-or-any-other-tw

I'll look into CL first due to a strong preference for interactivity

@vindarel
Copy link
Author

more fun: hygienic VS non-hygienic macros:

Hygienic macros are hygienic which traditional Lisp macros can never be. This is good.

But every implementation of them requires interpretative pseudoframe monoids, or stackable zone sets, or portal syntax taints. Usually the details of the implementation will change weekly depending on whose PhD thesis is now fashionable. It is so exhausting.

And over here are are traditional Lisp macros, and you can write a macroexpander for a simple Lisp dialect in an afternoon. while drinking coffee.

🤣

zyni-moe, reddit, 2024-01-27

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