Skip to content

Instantly share code, notes, and snippets.

@vindarel
Last active November 22, 2024 23:15
Show Gist options
  • 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:

@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

@alexispurslane
Copy link

alexispurslane commented May 24, 2024

God, thank you thank you thank you for writing this.

I was introduced to Racket as one of my first programming languages, and my first proper introduction to any Lisp/Scheme-family language, and I tried to make it my main language for years, and I honestly kind of hated using it. Sure it has S-expressions and macros, but at the end of the day it didn't feel much different from just writing a script in JS or Python; in fact, it felt much less dynamic and more rigid in many ways, since you can dynamically define variables and class members and such with JS and Python because "everything's a dict/object." And of course as you cover the ecosystem and development experience really wasn't great. So I was never able to stick to it.

Ever since that experience, I've been looking for some criticism of Racket to help me feel like I'm not crazy, because most people seem to think it's fine.

@vicho314
Copy link

vicho314 commented Oct 1, 2024

Scheme's R5RS version manual spans near 40 pages.
Racket docs are a full blown dense manual with many libraries.

You can do just ˋ(load "library.scm")ˋ on scheme, while on Racket you have to declare MODULES.

@attila-lendvai
Copy link

for a decade of CL hacking i always imagined Scheme to be a cleaner and leaner CL. then i got into scheme (because of Guix), and boy i was wrong...

there's practically no portability between schemes, or at least nothing close to CL. semantics is weird at places (why would you call an error handler in an env where the same error handler is still installed as the current error handler?!). and i have a really hard time learning my way into hygienic macros, even though i wrote a lot of complex metaprograms in CL.

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