Emacs is awesome because it nicely handles every programming language I use.
There was no mention in the article of the LispWorks editor, that was derived from Hemlock. A really nice editor to use when I need the features of the LispWorks IDE, otherwise my favorite is just Emacs configured for LispWorks and SBCL.
For the discussion topic: I am not sure if the LispWorks editor is faster, snappier, etc. than Emacs because it is compiled Common Lisp.
From the homepage: "CLiki contains resources for learning about and using the programming language Common Lisp, and information about DFSG-compliant free software implemented in Common Lisp."
LispWorks is proprietary commercial software and thus out-of-scope for CLIKI.
Btw., that's a reason I don't contribute to CLIKI, as I'm not interested in only "DFSG-compliant free software implemented in Common Lisp".
(edit: there's also https://github.com/nobody-famous/alive-lsp/ that is built for the Alive extension that brings great CL support to VSCode (usable but in the works right now).
You might also be interested in vundo: https://elpa.gnu.org/packages/vundo.html. It is a newer alternative that is to my knowledge more robust, but depends on Emacs 28.
Could you elaborate on "more robust"? I use undo tree currently and the readme suggests it has less features- does undo tree have problems that vundo solves? I don't mind undo tree needing to be enabled all the time or replacing undo commands.
I don't recall the implementation details, but I have heard of undo-tree landing in invalid states that can break the history. It might just be that vundo is newer, but I haven't heard of these kinds of stories for that package.
In my eyes it is the more idiomatic implementation.
I have not used vundo, but it seems to be just a visualizer for the buffer undo list, whereas undo-tree takes over the undo system, replacing not just the commands but the data structure (https://github.com/apchamberlain/undo-tree.el/blob/help-in-v...). In other words, I think there's simply less surface area for vundo to have or cause problems.
I’ve heard the same about undo-tree, was wondering if that was what you were referring to. I haven’t experienced it myself but maybe I’ll check out vundo before I do..
is there a tldr on undo-tree's capabilities? I really like emacs' default undo behaviour, especially it's region bound behavior. undo-tree is kind of like vim right? Ive actually never really grokked that one either. I even remove undo-tree after installing evil as its an unwanted change for me, and evil has no option not to use it.
Walking the tree of changes has proven very useful to me several times.
Undo-tree can also display the diff for each change. Useful when an operation induced changes in different parts of a long document (for example rerunning source code blocks with org-babel).
Undo tree stores the changes you make in a tree, like Emacs does by default, but its undo function is undo only and its redo function is redo only. When there are multiple different changes you can redo you can select which one you want.
Vundo offers that functionality with Emacs' default undo tree, making it an objectively better package as it preserves undo-in-region, which undo-tree lacks.
It is missing the Lem editor, that works for CL out of the box but also for more languages (Python, Rust, Go, Java, Dart, Nim, HTML… and a directory, markdown, SQL, shell… mode). https://github.com/lem-project/lem/ It works on the terminal and in an experimental Electron front-end. More are in the works. It lacks docstrings and documentation, but its gitter chat is somewhat active and different people showed interest in helping. It has a Vim layer.
It is an easy to install CL editor and REPL, so it's worth checking out for newcomers, it can help.
I have used Clojure on and off for probably 7 years. But when I tried to distribute my program which was a CLI tool, it proved incredibly painful. Clojure startup time is really bad over a second in the best case and it gets worse the more libraries you include. This is not a problem if you are writing a web application, but it's terrible for command line applications. The community seems thoroughly disinterested in solving this problem except with graalvm's native-image. I've done that route and believe me it's so painful.
Common Lisp has everything Clojure has. It feels like Rich Hickie took everything that he liked about Common Lisp and put it into Clojure. Many of the functions in Clojure were basically copied from Common Lisp: if-let, conj(oin), disj(oin) are some examples of core Clojure functions and macros that were totally stolen from Alexandria.
Even better, most CL implementations can save directly to an executable file. Embeddable Common Lisp is my favorite because its executable files are measured in kilobytes, something I could never do with native-image. And the startup time is amazing.
I did look at other lisp languages when deciding to move away from Clojure. However, Racket's standalone executables (raco exe) include the interpreter, and so are huge; Chez Scheme's ecosystem doesn't have a YAML library as far as I can tell, ditto for Chicken. Also scheme's library ecosystem in general (sans racket) is a bit lacking to me.
Common Lisp it is. It has its warts, but they're not too bad. It's long history also speaks of stability though. SBCL is crazy good optimized.
I wrote a small program in CL and Rust, and (SB)CL can run faster than Rust EVEN FROM SOURCE! It's just completely mindblowing how fast it starts.
If you don't believe me, write a program that does something like count how many times each letter appears in a text file in CL and Rust, then run them with `time`. I can pretty much guarantee CL runs as fast or faster.
EDIT: my comment is meant for anyone curious about OP's clamis, I am obviously just agreeing with their point about CL's startup speed.
Ooooh nice!!! That is amazing but how viable is common lisp for low level programming. Instead of embedding CL, what about a DSL that creates binaries, does something like this exist?
Last I checked, ECL binaries are around ~10-20 MiB (including the shared file) and the price of having these binary sizes is start-up time which is around 500-1000ms.
BTW, since you program professionally in CL, do you use Emacs? Doom or custom?
To be clear, unfortunately I do not program professionaly in CL. I use vim + vim-slime (jpalardy) + GNU screen + rlwrap. dotfiles here[1], here[2] and here[3].
It depends. Common Lisp is like C++ in that it’s a big multi-paradigm language. It supports functional, imperative, and object oriented programming out of the box. And thanks to macros libraries can add basically any paradigm you like to that list. Logic programming is one example. To me it feels like the lispiest Lisp. There is a large variety of libraries available. Many implementations can produce well optimized native code. Common Lisp is my personal go-to Lisp. If you want to learn Lisp for personal growth I believe it’s the best choice. There are jobs out there too.
Clojure is a good choice if the JVM is an option. You get access to the entire Java ecosystem. It’s been years since I’ve worked in Java land, but my understanding is the JVM is pretty fast now too. I like Clojure and it’s the only Lisp I’ve ever been paid to work in. I already knew Java, so my Common Lisp experience made it extremely easy to pick up. If you want to write Lisp professionally it’s not your only choice, but it could be the best.
Scheme is more focused on functional programming. I’ve only ever used it for studying computing science. I don’t know much about Racket, but at a glance it looks like a kind of Scheme++.
As far as I know, GNU Emacs is the most popular editor for all of the above. It’s largely written in Emacs Lisp, but the core and parts where performance is critical are C. Racket does come with its own editor, DrRacket, so maybe Racket users use that? I don’t know if it’s written in Racket but I’d suppose it is.
Incidentally, it’s my understanding that the Nyxt browser team intends to add full editing support at some point. If so, it will be a kind of web focused Emacs, which sounds interesting.
Some folks'd say that yeah, Common Lisp is the go-to Lisp. Some folks'd say no, the go-to is Scheme.
Guile is GNU's common language runtime, sorta like Java's JVM or Microsoft's CLR. And Scheme is really the only first-class language of Guile; to a lot of people "Guile" means "Scheme". I don't know of an Emacs-like using Scheme, but there is an effort to implement Emacs-Lisp on Guile, and have GNU Emacs ditch its Lisp interpreter in favor of Guile. This would allow Emacs to use any language that can run on Guile... which mostly means Scheme.
Beware of performance issues though. Guile is extraordinarily slow on numerical code at least. Specifically, orders of magnitude slower than Chez Scheme, while the latter is just a couple times slower than LuaJIT e.g. I got really turned off from Scheme after running some benchmarks on a couple implementations. Although I know that for people coming from say Python it may even be an upgrade.
Guile is the Python of Schemes. It is not meant to be performant, it is meant to be the glue that holds everything together in the GNU operating system.
That Python is the most popular language today should tell you how successful Guile has been at this goal.
If I ever take a sabbatical year then porting the C parts of GNU Emacs to Common Lisp is a project I’d love to do. Then one could host GNU Emacs in a CL image and get the whole package ecosystem. The end goal would to make CL and Elisp both valid choices for customization.
My implementation strategy would probably be to start by using FFI to reuse as much of the C code as possible and then incrementally rewrite it. Or not, maybe that wouldn’t even be necessary.
To be honest, I personally never understood this notion "of what Lisp should I choose?". For the first-timers, for learning - any Lisp would do, Clojure, Racket, Fennel, CL, Janet, even Emacs Lisp. Once you're through the basics - structural editing, REPL-driven workflow, etc., then switching between Lisps is not that difficult.
Yes, they are different languages, working atop different platforms. They have different semantics, vastly different core libraries, etc. Yet at the same time, somehow, there's little mental overhead when switching between them.
I don't have any difficulties moving between Fennel, Clojurescript, Clojure, Clojure-Dart, LFE. But if I had to manage writing code and maintain multiple projects in Lua, Javascript, Java, Erlang and Dart - I would claim that my name is Guy Stele Jr. and I am a very smart programmer. Alas, I'm not that smart, that's why I chose Lisp.
Kawa (like Clojure) runs on the JavaVM, but has a longer pedigree (from 1996), good compatibility with standard Scehemes (including R7RS), and has a stronger emphasis on performance: It has optional types and semi-decent type inferance so it is easy to write code as performant as Java. It also has fast startup, and is unopinonated on how you run and bundle applications: it generates pretty vanilla class files that interoperate with Java easily. See https://www.gnu.org/software/org and https://gitlab.com/kashell/Kawa
Sigh - two major typos, and I dont see a way to edit the answer. SO it should be "standard Schemes" and more importantly the URL is https://www.gnu.org/software/kawa
Making a step aside but the nyxt browser is built on commonlisp and gives an emacs UX for browsing + hackability. It's not an editor but it's a recent user programmable common lisp system. And who knows, maybe they'll embed a live editor in it.
For better or worse I think e-lisp is here to stay, with all its
quirks. I think of it as "text processing Lisp", much as I think Perl
is still a useful go-to for practical extraction and reporting. The
world of other Lisps is rich and bountiful. I'm a secret Schemer
myself and love Racket, but I'm not sure emacs needs re-writing in
fresher dialects. What's the main case, does anyone know? It might be
nice if e-lisp still had room to mature and incorporate some lessons
from younger Lisps.
I didn’t know that, but I have some personal biases because I have had 6 or 7 years of pure Common Lisp paid work, a little over 1 year of Clojure paid work, and a few months of paid Scheme work.
Common Lisp is probably the closest thing to a go-to lisp, but there are also Scheme and Clojure. Depending on your requirements and preferences, any of Scheme, Clojure, or CL might be the perfect choice.
Clojure doesn't have an Emacs-like but it does have Cursive (for IntelliJ) and CIDER (for Emacs, like SLIME).
Scheme has Guile Emacs (currently in an unfinished state, needs fiddling to even build) and Edwin (comes with MIT/GNU Scheme).
It's hard to give a blanket recommendation on a go-to lisp. I would probably recommend Clojure and Racket over CL. The biggest downside of lisps IMO is the lack of well documented, maintained libraries, and CL suffers from it more than most. For some use cases CL is a better choice, and the tooling is excellent, but it's hard to recommend.
As a rule whenever the question starts with "do people consider", the answer is going to be: some do, others don't.
If you wish to "look into" Lisp, do the work: look at a bunch of resources, skim them, pick the ones that look intersting.
Asking whether to look into something is sometimes just a way to procrastinate. Questions like yours (not just about Lisp, but definitely about Lisp as well) are asked every day, and answers are (i) repetitive and (ii) abound. Just do the work.
slightly more aggressive answer than I expected but ok.
so first, yea bad phrasing, but that question usually implies "majority of people".
second, I have done work. I have coded even stuff in clj and cljs. little elisp. but I am not in contact with anyone doing lisp so I am disconnected from the "lisp community". hence my question.
in any case, my question still stands, but this time as "I'd love to get some opinions about lisps being used nowadays, and if there are emacsen in those".
There is no "Lisp community". In this family of languages, there are a bunch of individuals that sometimes form communities around areas of interest or particular fora.
If you looked into Clojure and Elisp, looking into Common Lisp or some Schemes could still be valuable, sure. All of them are in use. You can visit the relevant subreddits or chat channels or mailing lists to "get connected". Maybe even find some meetups or submit pull requests.
As far as I know there are no Emacsen in popular use today except GNU Emacs. There are some editors "inspired" by Emacs that are developed and possibly used by a few. These may be interesting and you may find them usable, but I'm not sure their authors would consider them part of the family of Emacsen just yet.
If common lisp is the go-to Lisp, that's a sad indictment of Lisp itself. By commit counts in Github in first quarter of 2022, it doesn't even break into top 50 languages [1]. Surely a flawed metric, but it's damning when you have Elisp - configuration language for a freaking text editor - at #25, and Clojure at #28.
What? Wasn't ANSI CL standardized in 1994? Besides incremental performance and security improvements, what needs to change?
Compare this to other popular languages from C++ to Python, which surely generate tons of additional work by continually changing the languages themselves.
There are a lot of redundancies in the language standard library caused by it being an amalgamation of multiple prior Lisps. Later standards could have deprecated some of those and then later removed them to provide a cleaner system, but they were needed in order to achieve the goal of mostly supporting other Lisps out of the box at the time of the standard (that is, with few or no code changes). elt and nth as examples. The former is generic, works on any sequence, the latter is list specific. In practice, what's the reason (besides backwards compatibility) to have both of these? There are other list-only functions which either have an equivalent sequence function or reasonably could if they don't. This would have been a natural improvement over time. Even if there was a lot of debate, Lisp being Lisp means you could always keep a package around for each prior set of the standard library. The later standards would have you start a package not based on the :cl package but on, say, the :cl99 package or :cl05 package. If you needed the deprecated/eliminated features, you'd use :cl94 or import specific symbols from it if you didn't want it all.
It would also be nice to see a greater adoption of "sequence" (which has a limited set of things that qualify) being opened up so that user-defined sequences could be used with existing sequence processing functions. Same for numbers and other things. Allowing (performance is a valid concern here, though) more generic functions would open up more interesting developments later. See Julia and its application in the numerical computing domain. You can do that kind of computing in CL, but you can't use the existing arithmetic and numeric functions because they're only generic to the limit of the defined numeric tower and can't be extended beyond that.
Concurrency, totally absent in the language standard, for better or worse. On the one hand you don't necessarily want to bless a particular concurrency model, and Common Lisp is nothing if not a toolbox language (pick your base capabilities and grow it to fit your application). So you'd want some low-level primitives that can be composed rather than blessing one or two particular models. But without standardization, this isn't happening. You do have Bordeaux-threads which basically gives you a portable threads interface by mapping to each CL implementation's specific threading library. But threads can be heavyweight compared to other options, and BT limits you to the lowest common denominator across the implementations. People have built useful abstractions on top of it, still. And some implementation could always implement something like coroutines and a thread pool for distributing them, but it would be implementation specific rather than standard. Even having that as a baseline model, leaving specifics of implementation open but locking down semantics, would be a good development for CL.
And Lisp is almost uniquely able to handle transitions to later standards as I described above. You don't actually have to forfeit backwards compatibility entirely or at all if the changes are handled by moving to a new default base package. :cl-user/:cl become :cl##-user/:cl##. Accessing old features is still feasible.
> And Lisp is almost uniquely able to handle transitions to later standards as I described above. You don't actually have to forfeit backwards compatibility entirely or at all if the changes are handled by moving to a new default base package. :cl-user/:cl become :cl##-user/:cl##
Go use cl21[0] if you care for this sort of thing.
> more generic functions would open up more interesting developments later
generic-cl[1]. But in a prefix-oriented language, I just don't see this as particularly important.
> you don't necessarily want to bless a particular concurrency model
You do[2]; this is one of the notable deficiencies in the cl standard that really bites, today. It is being worked on.
> Go use cl21[0] if you care for this sort of thing.
Right, it demonstrates what I'm saying about the relative ease for CL to move forward. You'll still need to bring the implementations onboard though to be really successful. See the note in the generic-cl link about a potential performance hit (and then how to work around it) because of increased use of generic functions. Implementations can improve their performance around generic functions and method dispatch, but users (like those developing cl21 and generic-cl) aren't going to do so on their own as easily or portably. Having an actual collective standards body working on a real cl2x standard would be critical to getting all implementations moving on this.
> You do[2]; this is one of the notable deficiencies in the cl standard that really bites, today. It is being worked on.
Are all implementations moving towards some common better approach today? Or are we still stuck with bordeaux-threads (and anything built on that) as pretty much the only portable way to do concurrency in CL?
What I mean by blessing a particular model, though:
Do you use a shared-nothing BEAM style? Mailboxes per process (what is a process?)? Channels that can be passed around? Coroutines? Asyncio style? Structured concurrency? None of the above? All of the above?
CL has always been a toolbox language, many of the things programmers use actually map down to more primitive elements (even defun is a macro and you can provide your own, see SERIES and SCREAMER for examples). So instead of presenting a high-level Go-styled concurrency model or insisting on structured concurrency it would be more in keeping with CL's history to provide the baseline features that enable better concurrency (and uniform across implementations) and then let people build on that. Higher level libraries can come along later (see how CLOS came out of earlier developments like Flavors and CommonLoops), and maybe one of those can be blessed by becoming part of the standard. But the primitives will remain so variations will remain possible for those who want them.
The issues in the first two paragraphs there are addressable at the user level: just import from a package other than COMMON-LISP, where things are implemented to be more to your liking.
So, what you actually want is that doing this could be done in a way that everything is as efficient as if one invoked the CL built-in functions. I think
a little more smarts in CL compilers could do this, in particular
efficient invocation of generic functions when the argument classes are known
at compile time (doing this in a way that allows methods to be added or redefined requires some care but can be done.)
Right, cleanup stuffs like I started off with would be easy enough to do now. And reasonably common extensions are covered by things like Alexandria. But going to more generics introduces a potential performance hit without the implementations being onboard to improve how they handle generic functions and method dispatch. And then there are other enhancements (like concurrency) that are bounded, with regards to portability, by whatever implementations uniformly make available. So any changes there will require implementations to be involved if it's going to result in portable code. Otherwise you'll have people implementing things using, maybe, CFFI and tying it to a particular implementation, OS, and set of external libraries, which breaks portability.
I'd argue genericizing a built-in won't impose a performance penalty on anything it currently is required to do. That's because it already has to dispatch on the classes it does handle, and also should recognize and error when it's given a class it doesn't. Adding more cases just means replacing the old error case with more decisions (if dispatch is implemented by a decision tree), or expanding the hash table (if dispatch is handled by the usual CLOS dispatch table.)
There is a general philosophy in the design of Common Lisp: expose to the user facilities that are used by an implementation for the implementation of built-ins. I don't think Common Lisp is quite complete in this respect, but this would be the place to extend it.
Thing is you don't have an alternative for ELisp. If you want to configure or/and extend Emacs, you've to use it. Common Lisp doesn't have such a strong connection to any platform. Nevertheless checking the list it comes as a surprise that languages like Smalltalk, Erlang, Groovy, Lean (a freaking theorem prover) are in but not Common Lisp.
That's true. However consider the context that: i) Emacs has stopped appearing even at the bottom of popular surveys like stackoverflow years ago ii) Most Emacs users probably aren't too heavily into customisation iii) Or they likely already achieved their heavily customised system years ago, and mostly enjoy stability nowadays (that's me) iv) Most customisations are too personal in nature and aren't published online (also me)
Given that, I think for Elisp to still come at #25 in this metric is a huge credit to its ecosystem for sure, but I still think that puts into perspective how much of a non-entity Common Lisp has become.
What tooling are people using to write UI's in common lisp?
Is it difficult to distribute ?
I've been using croatoan for a ncurses text interface, but I fear that i'll need to write something more "guish" in the next few months for the terminal afraid.
He was working on a conversion of emacs from elisp to common lisp, but I don’t think he got very far on the project before he fell ill. He never shared many details about it, that I know of.
Emacs is awesome because it nicely handles every programming language I use.
There was no mention in the article of the LispWorks editor, that was derived from Hemlock. A really nice editor to use when I need the features of the LispWorks IDE, otherwise my favorite is just Emacs configured for LispWorks and SBCL.
For the discussion topic: I am not sure if the LispWorks editor is faster, snappier, etc. than Emacs because it is compiled Common Lisp.
CLIKI is about free and open source software.
From the homepage: "CLiki contains resources for learning about and using the programming language Common Lisp, and information about DFSG-compliant free software implemented in Common Lisp."
LispWorks is proprietary commercial software and thus out-of-scope for CLIKI.
Btw., that's a reason I don't contribute to CLIKI, as I'm not interested in only "DFSG-compliant free software implemented in Common Lisp".
The performance sensitive parts of Emacs are written in C, which would explain why you don’t see a huge difference between Emacs and LW imo
It's nice to see more Emacsen, though without something like eglot or lsp-mode I don't think they'll really take off.
That said, I am very fond of the undo-tree package for Emacs and I doubt I could switch to any editor that doesn't have something similar.
The good news is that Eglot is very likely going to be included with Emacs 29.1. See https://lists.gnu.org/archive/html/emacs-devel/2022-09/msg01... for a discussion on this topic.
Unless I'm mistaken that means it won't be included out of the box but will instead be available to download and install from ELPA, right?
Eglot already is available from ELPA, I think they actually are planning on including it in the box of batteries that Emacs ships with.
Oh wow, that’s awesome. I had thought LSP mode was more popular but I prefer eglot so that works for me.
Lem uses its LSP mode. https://github.com/lem-project/lem/ (don't know much more, maybe it is that one (same author) https://github.com/cxxxr/cl-lsp)
(edit: there's also https://github.com/nobody-famous/alive-lsp/ that is built for the Alive extension that brings great CL support to VSCode (usable but in the works right now).
Neat, I'll keep an eye on Lem, thank you for bringing it to my attention!
I have used Emacs for decades and TIL about undo-tree. Thank you!
You might also be interested in vundo: https://elpa.gnu.org/packages/vundo.html. It is a newer alternative that is to my knowledge more robust, but depends on Emacs 28.
Could you elaborate on "more robust"? I use undo tree currently and the readme suggests it has less features- does undo tree have problems that vundo solves? I don't mind undo tree needing to be enabled all the time or replacing undo commands.
I don't recall the implementation details, but I have heard of undo-tree landing in invalid states that can break the history. It might just be that vundo is newer, but I haven't heard of these kinds of stories for that package.
In my eyes it is the more idiomatic implementation.
I have not used vundo, but it seems to be just a visualizer for the buffer undo list, whereas undo-tree takes over the undo system, replacing not just the commands but the data structure (https://github.com/apchamberlain/undo-tree.el/blob/help-in-v...). In other words, I think there's simply less surface area for vundo to have or cause problems.
This is a good summary.
I’ve heard the same about undo-tree, was wondering if that was what you were referring to. I haven’t experienced it myself but maybe I’ll check out vundo before I do..
is there a tldr on undo-tree's capabilities? I really like emacs' default undo behaviour, especially it's region bound behavior. undo-tree is kind of like vim right? Ive actually never really grokked that one either. I even remove undo-tree after installing evil as its an unwanted change for me, and evil has no option not to use it.
Walking the tree of changes has proven very useful to me several times.
Undo-tree can also display the diff for each change. Useful when an operation induced changes in different parts of a long document (for example rerunning source code blocks with org-babel).
Undo tree stores the changes you make in a tree, like Emacs does by default, but its undo function is undo only and its redo function is redo only. When there are multiple different changes you can redo you can select which one you want.
Vundo offers that functionality with Emacs' default undo tree, making it an objectively better package as it preserves undo-in-region, which undo-tree lacks.
I might take a look at vundo then, that sounds great. Thank you both for the explanations!
It is missing the Lem editor, that works for CL out of the box but also for more languages (Python, Rust, Go, Java, Dart, Nim, HTML… and a directory, markdown, SQL, shell… mode). https://github.com/lem-project/lem/ It works on the terminal and in an experimental Electron front-end. More are in the works. It lacks docstrings and documentation, but its gitter chat is somewhat active and different people showed interest in helping. It has a Vim layer.
It is an easy to install CL editor and REPL, so it's worth checking out for newcomers, it can help.
https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
I'm really curious: do people consider common lisp to be the go-to lisp today?
if yes, that's awesome, I'll look into it.
if no, what is the go-to? and is there an emacs-like using that lisp?
I have used Clojure on and off for probably 7 years. But when I tried to distribute my program which was a CLI tool, it proved incredibly painful. Clojure startup time is really bad over a second in the best case and it gets worse the more libraries you include. This is not a problem if you are writing a web application, but it's terrible for command line applications. The community seems thoroughly disinterested in solving this problem except with graalvm's native-image. I've done that route and believe me it's so painful.
Common Lisp has everything Clojure has. It feels like Rich Hickie took everything that he liked about Common Lisp and put it into Clojure. Many of the functions in Clojure were basically copied from Common Lisp: if-let, conj(oin), disj(oin) are some examples of core Clojure functions and macros that were totally stolen from Alexandria.
Even better, most CL implementations can save directly to an executable file. Embeddable Common Lisp is my favorite because its executable files are measured in kilobytes, something I could never do with native-image. And the startup time is amazing.
I did look at other lisp languages when deciding to move away from Clojure. However, Racket's standalone executables (raco exe) include the interpreter, and so are huge; Chez Scheme's ecosystem doesn't have a YAML library as far as I can tell, ditto for Chicken. Also scheme's library ecosystem in general (sans racket) is a bit lacking to me.
Common Lisp it is. It has its warts, but they're not too bad. It's long history also speaks of stability though. SBCL is crazy good optimized.
For CLIs, Common Lisp is excellent.
I wrote a small program in CL and Rust, and (SB)CL can run faster than Rust EVEN FROM SOURCE! It's just completely mindblowing how fast it starts.
If you don't believe me, write a program that does something like count how many times each letter appears in a text file in CL and Rust, then run them with `time`. I can pretty much guarantee CL runs as fast or faster.
EDIT: my comment is meant for anyone curious about OP's clamis, I am obviously just agreeing with their point about CL's startup speed.
Ooooh nice!!! That is amazing but how viable is common lisp for low level programming. Instead of embedding CL, what about a DSL that creates binaries, does something like this exist?
For embedded application (as in micro-controllers) there is http://www.ulisp.com/
SBCL still needs garbage collection. There are also https://github.com/carp-lang/Carp and https://github.com/bakpakin/Fennel
I haven't used these. Would be great if low-level and embedded engineers could chime in.
Clojure now has Babashka and better integration with GraalVM if you are interested in creating CLI tools. Worth checking out.
Last I checked, ECL binaries are around ~10-20 MiB (including the shared file) and the price of having these binary sizes is start-up time which is around 500-1000ms.
BTW, since you program professionally in CL, do you use Emacs? Doom or custom?
To be clear, unfortunately I do not program professionaly in CL. I use vim + vim-slime (jpalardy) + GNU screen + rlwrap. dotfiles here[1], here[2] and here[3].
Blog post about this will be written subsequently at https://blog.djha.skin .
1: https://git.sr.ht/~djha-skin/dotfiles/tree/main/item/dot-con...
2: https://git.sr.ht/~djha-skin/dotfiles/tree/main/item/dot-loc...
3: https://git.sr.ht/~djha-skin/dotfiles/tree/main/item/dot-scr...
Very cool! Thanks for sharing the dots!
I'm a vim user too, but recently I've been considering Common Lisp mainly due to this post: https://mikelevins.github.io/posts/2020-12-18-repl-driven/
so I did a brief tour on Emacs (cause everyone uses sly) but both Emacs and CL take too much time so I've postponed them.
Would be nice if you describe your vim+cl workflow and how does it hold up to Emacs+Sly+Org-mode ™
https://blog.djha.skin/blog/developing-common-lisp-using-gnu...
Thanks!
It depends. Common Lisp is like C++ in that it’s a big multi-paradigm language. It supports functional, imperative, and object oriented programming out of the box. And thanks to macros libraries can add basically any paradigm you like to that list. Logic programming is one example. To me it feels like the lispiest Lisp. There is a large variety of libraries available. Many implementations can produce well optimized native code. Common Lisp is my personal go-to Lisp. If you want to learn Lisp for personal growth I believe it’s the best choice. There are jobs out there too.
Clojure is a good choice if the JVM is an option. You get access to the entire Java ecosystem. It’s been years since I’ve worked in Java land, but my understanding is the JVM is pretty fast now too. I like Clojure and it’s the only Lisp I’ve ever been paid to work in. I already knew Java, so my Common Lisp experience made it extremely easy to pick up. If you want to write Lisp professionally it’s not your only choice, but it could be the best.
Scheme is more focused on functional programming. I’ve only ever used it for studying computing science. I don’t know much about Racket, but at a glance it looks like a kind of Scheme++.
As far as I know, GNU Emacs is the most popular editor for all of the above. It’s largely written in Emacs Lisp, but the core and parts where performance is critical are C. Racket does come with its own editor, DrRacket, so maybe Racket users use that? I don’t know if it’s written in Racket but I’d suppose it is.
Incidentally, it’s my understanding that the Nyxt browser team intends to add full editing support at some point. If so, it will be a kind of web focused Emacs, which sounds interesting.
The original version of DrRacket was written in C, but it has been rewritten in Racket a long time ago. https://github.com/racket/drracket
I use a mix of DrRacket, WinEdt and Geany (with more color in the matched parenthesis).
Some folks'd say that yeah, Common Lisp is the go-to Lisp. Some folks'd say no, the go-to is Scheme.
Guile is GNU's common language runtime, sorta like Java's JVM or Microsoft's CLR. And Scheme is really the only first-class language of Guile; to a lot of people "Guile" means "Scheme". I don't know of an Emacs-like using Scheme, but there is an effort to implement Emacs-Lisp on Guile, and have GNU Emacs ditch its Lisp interpreter in favor of Guile. This would allow Emacs to use any language that can run on Guile... which mostly means Scheme.
Beware of performance issues though. Guile is extraordinarily slow on numerical code at least. Specifically, orders of magnitude slower than Chez Scheme, while the latter is just a couple times slower than LuaJIT e.g. I got really turned off from Scheme after running some benchmarks on a couple implementations. Although I know that for people coming from say Python it may even be an upgrade.
Guile is the Python of Schemes. It is not meant to be performant, it is meant to be the glue that holds everything together in the GNU operating system.
That Python is the most popular language today should tell you how successful Guile has been at this goal.
I thought Gauche was the Python of Schemes: not super fast, but with a lot* of included batteries.
* See https://practical-scheme.net/gauche/man/gauche-refe/Library-... for an overview.
If I ever take a sabbatical year then porting the C parts of GNU Emacs to Common Lisp is a project I’d love to do. Then one could host GNU Emacs in a CL image and get the whole package ecosystem. The end goal would to make CL and Elisp both valid choices for customization.
My implementation strategy would probably be to start by using FFI to reuse as much of the C code as possible and then incrementally rewrite it. Or not, maybe that wouldn’t even be necessary.
To be honest, I personally never understood this notion "of what Lisp should I choose?". For the first-timers, for learning - any Lisp would do, Clojure, Racket, Fennel, CL, Janet, even Emacs Lisp. Once you're through the basics - structural editing, REPL-driven workflow, etc., then switching between Lisps is not that difficult.
Yes, they are different languages, working atop different platforms. They have different semantics, vastly different core libraries, etc. Yet at the same time, somehow, there's little mental overhead when switching between them.
I don't have any difficulties moving between Fennel, Clojurescript, Clojure, Clojure-Dart, LFE. But if I had to manage writing code and maintain multiple projects in Lua, Javascript, Java, Erlang and Dart - I would claim that my name is Guy Stele Jr. and I am a very smart programmer. Alas, I'm not that smart, that's why I chose Lisp.
Common Lisp, Scheme and Clojure. Try each three and see which you like. I prefer CL, but that's because I develop programs in the large.
Kawa (like Clojure) runs on the JavaVM, but has a longer pedigree (from 1996), good compatibility with standard Scehemes (including R7RS), and has a stronger emphasis on performance: It has optional types and semi-decent type inferance so it is easy to write code as performant as Java. It also has fast startup, and is unopinonated on how you run and bundle applications: it generates pretty vanilla class files that interoperate with Java easily. See https://www.gnu.org/software/org and https://gitlab.com/kashell/Kawa
Sigh - two major typos, and I dont see a way to edit the answer. SO it should be "standard Schemes" and more importantly the URL is https://www.gnu.org/software/kawa
Making a step aside but the nyxt browser is built on commonlisp and gives an emacs UX for browsing + hackability. It's not an editor but it's a recent user programmable common lisp system. And who knows, maybe they'll embed a live editor in it.
For better or worse I think e-lisp is here to stay, with all its quirks. I think of it as "text processing Lisp", much as I think Perl is still a useful go-to for practical extraction and reporting. The world of other Lisps is rich and bountiful. I'm a secret Schemer myself and love Racket, but I'm not sure emacs needs re-writing in fresher dialects. What's the main case, does anyone know? It might be nice if e-lisp still had room to mature and incorporate some lessons from younger Lisps.
Clojure is the biggest lisp by far if we measure by amount of programmers getting paid to write it.
I didn’t know that, but I have some personal biases because I have had 6 or 7 years of pure Common Lisp paid work, a little over 1 year of Clojure paid work, and a few months of paid Scheme work.
In my opinion, Common Lisp is the environment to develop informed opinions about the tradeoffs and benefits of other forms of Lisp.
While you can compare Scheme to Clojure and Clojure to Racket, Common Lisp embodies the alternatives against which each was developed.
Common Lisp is probably the closest thing to a go-to lisp, but there are also Scheme and Clojure. Depending on your requirements and preferences, any of Scheme, Clojure, or CL might be the perfect choice.
Clojure doesn't have an Emacs-like but it does have Cursive (for IntelliJ) and CIDER (for Emacs, like SLIME).
Scheme has Guile Emacs (currently in an unfinished state, needs fiddling to even build) and Edwin (comes with MIT/GNU Scheme).
It's hard to give a blanket recommendation on a go-to lisp. I would probably recommend Clojure and Racket over CL. The biggest downside of lisps IMO is the lack of well documented, maintained libraries, and CL suffers from it more than most. For some use cases CL is a better choice, and the tooling is excellent, but it's hard to recommend.
Are there numbers on the LoC of libraries for each of these?
As a rule whenever the question starts with "do people consider", the answer is going to be: some do, others don't.
If you wish to "look into" Lisp, do the work: look at a bunch of resources, skim them, pick the ones that look intersting.
Asking whether to look into something is sometimes just a way to procrastinate. Questions like yours (not just about Lisp, but definitely about Lisp as well) are asked every day, and answers are (i) repetitive and (ii) abound. Just do the work.
slightly more aggressive answer than I expected but ok.
so first, yea bad phrasing, but that question usually implies "majority of people".
second, I have done work. I have coded even stuff in clj and cljs. little elisp. but I am not in contact with anyone doing lisp so I am disconnected from the "lisp community". hence my question.
in any case, my question still stands, but this time as "I'd love to get some opinions about lisps being used nowadays, and if there are emacsen in those".
I did not mean to be aggressive, just direct.
There is no "Lisp community". In this family of languages, there are a bunch of individuals that sometimes form communities around areas of interest or particular fora.
If you looked into Clojure and Elisp, looking into Common Lisp or some Schemes could still be valuable, sure. All of them are in use. You can visit the relevant subreddits or chat channels or mailing lists to "get connected". Maybe even find some meetups or submit pull requests.
As far as I know there are no Emacsen in popular use today except GNU Emacs. There are some editors "inspired" by Emacs that are developed and possibly used by a few. These may be interesting and you may find them usable, but I'm not sure their authors would consider them part of the family of Emacsen just yet.
If common lisp is the go-to Lisp, that's a sad indictment of Lisp itself. By commit counts in Github in first quarter of 2022, it doesn't even break into top 50 languages [1]. Surely a flawed metric, but it's damning when you have Elisp - configuration language for a freaking text editor - at #25, and Clojure at #28.
[1] https://madnight.github.io/githut/#/pushes/2022/1
What? Wasn't ANSI CL standardized in 1994? Besides incremental performance and security improvements, what needs to change?
Compare this to other popular languages from C++ to Python, which surely generate tons of additional work by continually changing the languages themselves.
This is referring to commits across all repos using those languages, not commits to the languages themselves.
There are a lot of redundancies in the language standard library caused by it being an amalgamation of multiple prior Lisps. Later standards could have deprecated some of those and then later removed them to provide a cleaner system, but they were needed in order to achieve the goal of mostly supporting other Lisps out of the box at the time of the standard (that is, with few or no code changes). elt and nth as examples. The former is generic, works on any sequence, the latter is list specific. In practice, what's the reason (besides backwards compatibility) to have both of these? There are other list-only functions which either have an equivalent sequence function or reasonably could if they don't. This would have been a natural improvement over time. Even if there was a lot of debate, Lisp being Lisp means you could always keep a package around for each prior set of the standard library. The later standards would have you start a package not based on the :cl package but on, say, the :cl99 package or :cl05 package. If you needed the deprecated/eliminated features, you'd use :cl94 or import specific symbols from it if you didn't want it all.
It would also be nice to see a greater adoption of "sequence" (which has a limited set of things that qualify) being opened up so that user-defined sequences could be used with existing sequence processing functions. Same for numbers and other things. Allowing (performance is a valid concern here, though) more generic functions would open up more interesting developments later. See Julia and its application in the numerical computing domain. You can do that kind of computing in CL, but you can't use the existing arithmetic and numeric functions because they're only generic to the limit of the defined numeric tower and can't be extended beyond that.
Concurrency, totally absent in the language standard, for better or worse. On the one hand you don't necessarily want to bless a particular concurrency model, and Common Lisp is nothing if not a toolbox language (pick your base capabilities and grow it to fit your application). So you'd want some low-level primitives that can be composed rather than blessing one or two particular models. But without standardization, this isn't happening. You do have Bordeaux-threads which basically gives you a portable threads interface by mapping to each CL implementation's specific threading library. But threads can be heavyweight compared to other options, and BT limits you to the lowest common denominator across the implementations. People have built useful abstractions on top of it, still. And some implementation could always implement something like coroutines and a thread pool for distributing them, but it would be implementation specific rather than standard. Even having that as a baseline model, leaving specifics of implementation open but locking down semantics, would be a good development for CL.
And Lisp is almost uniquely able to handle transitions to later standards as I described above. You don't actually have to forfeit backwards compatibility entirely or at all if the changes are handled by moving to a new default base package. :cl-user/:cl become :cl##-user/:cl##. Accessing old features is still feasible.
> And Lisp is almost uniquely able to handle transitions to later standards as I described above. You don't actually have to forfeit backwards compatibility entirely or at all if the changes are handled by moving to a new default base package. :cl-user/:cl become :cl##-user/:cl##
Go use cl21[0] if you care for this sort of thing.
> more generic functions would open up more interesting developments later
generic-cl[1]. But in a prefix-oriented language, I just don't see this as particularly important.
> you don't necessarily want to bless a particular concurrency model
You do[2]; this is one of the notable deficiencies in the cl standard that really bites, today. It is being worked on.
0. http://cl21.org/
1. https://github.com/alex-gutev/generic-cl
2. https://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf
> Go use cl21[0] if you care for this sort of thing.
Right, it demonstrates what I'm saying about the relative ease for CL to move forward. You'll still need to bring the implementations onboard though to be really successful. See the note in the generic-cl link about a potential performance hit (and then how to work around it) because of increased use of generic functions. Implementations can improve their performance around generic functions and method dispatch, but users (like those developing cl21 and generic-cl) aren't going to do so on their own as easily or portably. Having an actual collective standards body working on a real cl2x standard would be critical to getting all implementations moving on this.
> You do[2]; this is one of the notable deficiencies in the cl standard that really bites, today. It is being worked on.
Are all implementations moving towards some common better approach today? Or are we still stuck with bordeaux-threads (and anything built on that) as pretty much the only portable way to do concurrency in CL?
What I mean by blessing a particular model, though:
Do you use a shared-nothing BEAM style? Mailboxes per process (what is a process?)? Channels that can be passed around? Coroutines? Asyncio style? Structured concurrency? None of the above? All of the above?
CL has always been a toolbox language, many of the things programmers use actually map down to more primitive elements (even defun is a macro and you can provide your own, see SERIES and SCREAMER for examples). So instead of presenting a high-level Go-styled concurrency model or insisting on structured concurrency it would be more in keeping with CL's history to provide the baseline features that enable better concurrency (and uniform across implementations) and then let people build on that. Higher level libraries can come along later (see how CLOS came out of earlier developments like Flavors and CommonLoops), and maybe one of those can be blessed by becoming part of the standard. But the primitives will remain so variations will remain possible for those who want them.
The issues in the first two paragraphs there are addressable at the user level: just import from a package other than COMMON-LISP, where things are implemented to be more to your liking.
So, what you actually want is that doing this could be done in a way that everything is as efficient as if one invoked the CL built-in functions. I think a little more smarts in CL compilers could do this, in particular efficient invocation of generic functions when the argument classes are known at compile time (doing this in a way that allows methods to be added or redefined requires some care but can be done.)
Right, cleanup stuffs like I started off with would be easy enough to do now. And reasonably common extensions are covered by things like Alexandria. But going to more generics introduces a potential performance hit without the implementations being onboard to improve how they handle generic functions and method dispatch. And then there are other enhancements (like concurrency) that are bounded, with regards to portability, by whatever implementations uniformly make available. So any changes there will require implementations to be involved if it's going to result in portable code. Otherwise you'll have people implementing things using, maybe, CFFI and tying it to a particular implementation, OS, and set of external libraries, which breaks portability.
I'd argue genericizing a built-in won't impose a performance penalty on anything it currently is required to do. That's because it already has to dispatch on the classes it does handle, and also should recognize and error when it's given a class it doesn't. Adding more cases just means replacing the old error case with more decisions (if dispatch is implemented by a decision tree), or expanding the hash table (if dispatch is handled by the usual CLOS dispatch table.)
There is a general philosophy in the design of Common Lisp: expose to the user facilities that are used by an implementation for the implementation of built-ins. I don't think Common Lisp is quite complete in this respect, but this would be the place to extend it.
Thing is you don't have an alternative for ELisp. If you want to configure or/and extend Emacs, you've to use it. Common Lisp doesn't have such a strong connection to any platform. Nevertheless checking the list it comes as a surprise that languages like Smalltalk, Erlang, Groovy, Lean (a freaking theorem prover) are in but not Common Lisp.
That's true. However consider the context that: i) Emacs has stopped appearing even at the bottom of popular surveys like stackoverflow years ago ii) Most Emacs users probably aren't too heavily into customisation iii) Or they likely already achieved their heavily customised system years ago, and mostly enjoy stability nowadays (that's me) iv) Most customisations are too personal in nature and aren't published online (also me)
Given that, I think for Elisp to still come at #25 in this metric is a huge credit to its ecosystem for sure, but I still think that puts into perspective how much of a non-entity Common Lisp has become.
What tooling are people using to write UI's in common lisp? Is it difficult to distribute ?
I've been using croatoan for a ncurses text interface, but I fear that i'll need to write something more "guish" in the next few months for the terminal afraid.
Wasn't Erik Naggum doing something like this, too?
If he did he never published it. In fact, AFAIK Erik never published any code at all.
He did publish some elisp code, which you can see traces of in GNU Emacs and SLIME.
Res ipsa loquitur.
Nemo judex in causa sua.
Non vere curare quid Nemo habet dicere de illo.
(Miror si haec prima flammae latinae in interrete est.)
"interrete"
Heh.
He was working on a conversion of emacs from elisp to common lisp, but I don’t think he got very far on the project before he fell ill. He never shared many details about it, that I know of.