State of Common Lisp Survey 2020
docs.google.com
docs.google.com
- CL is mostly used by hobbyists. (Not a very big surprise.)
- There do seem to be several users in research computing. (As a computational biologist, I find this interesting and encouraging.)
- The user demographics skew towards younger adults (<45 yrs). (That's interesting because they weren't around yet during Lisp's heyday, so the language seems to retain enough appeal to still attract new users.)
- User's top 5 countries of origin: USA (30%), Germany (10%), UK (5.4%), Japan (5%), Canada (4.3%). (Not quite as anglophone-leaning as I'd expected; there's actually a very wide spread of countries represented.)
However, I don't know how this survey was advertised, so the results may just be sampling bias.
I'd be careful interpreting numbers like those. This isn't measuring the age demographics of CL users, per se. It's measuring the age demographics of people who responded to the survey. ~25% of that group self-reported as not actually being (current) lisp users.
Including people who don't actively use lisp in the sample is entirely valid, and capturing that information about them would facilitate some interesting analyses. For example, we could look for demographic differences among professional lispers, hobbyist lispers, and curious onlookers. Or see if there are any industry trends.
It's just that this Google doc reports these data in a way that's too coarse-grained to support that kind of analysis, regardless of any bias concerns.
I created this survey. I originally posted it to the CL subreddit and the CL IRC channel, so somewhat limited communication channels. Maybe there are other, better places to post it?
Also, contacting one of the people associated with a blog listed on Planet Lisp [2] would ensure that it appears there and might be seen by a wide yet relevant audience.
Now there are lists with almost 400 answers with most of the answers being practically the same ("personal stuff", "personal projects", "personal things"...). It does not make it easy to digest the information.
Which is actually kind of fine with me. After a long long period of people only being interested in asking questions when the answer can be graphed, it's nice to see some individuals' actual feelings and opinions showing through in the results. For example, "all tasks that do not require close OS functionality" was a gem of a response that you'd never see in a survey that consisted solely of checkboxes and radio buttons.
(for the lucky 10,000: http://www.winestockwebdesign.com/Essays/Lisp_Curse.html)
The request "Update on October 6, 2017. N.B.: Please stop submitting this to Hacker News!" should be interpreted in its strongest form: i.e. including comments.
> "Making Scheme object-oriented is a sophomore homework assignment."
Demonstrating basic OOP in C is likewise a suitable homework assignment.
http://rosettacode.org/wiki/Inheritance/Single/C
Making a viable object-oriented programming system for others to use is not a trivial task in any language.
No object system for Scheme that people actually use had been written by a sophomore as homework and gone into production in that state. (Linux started by a school kid tinkering with kernel programming too; but it would be a strawman to say that a bright undergrad can make a serious Unix clone in a few weeks that Amazon can put into the cloud and sell services on.)
The Common Lisp object system took many people years of work, and integrates deeply into the language, such that every object type has a class and can participate meaningfully in the object system without being wrapped in a class.
> Due to the difficulty of making C object oriented, only two serious attempts at the problem have made any traction: C++ and Objective-C.
Those are examples of having enough traction to actually get people to switch from C to a new language.
Ad hoc object systems have been implemented in C programs umpteen times, and a number of such things are available, or have been historically available, as formal libraries for use in C programs.
These all have "traction" in their "respective" projects and ecosystems; there is a lot of OOP action within C.
Including CLOS-like OO extensions for C.
Like Dynace:
Anyhow, in this instance you're right that there isn't even a need for open fields, there's enough examples online already of IT being separated into distinct sectors for field selection on forms.
But what really grated me the most about the results was that there didn't even seem to be any deduping of the results (or if there was, it was case sensitive):
("Everything" "everything")
("Personal" "projects")
("web development" "Web development")
And there was even an instance where prototyping appeared twice because one instance had \s afterwards!Programming language selection however really does not matter that much. I have also been very happy working on projects using Java, Python, JavaScript, and Ruby.
I would never try to talk anyone out of using whatever programming language is their favorite.
I think surveys like this are representative of dark matter programmers - Clojure over time changed from a hobby to work language.
• 40% interact with the Common Lisp (CL) community on Reddit and 32% on IRC. Indeed, in my experience too https://www.reddit.com/r/lisp/ and Freenode #lisp channels have active and supportive CL communities.
• 89% use SBCL. This is not surprising. SBCL has been the most popular Common Lisp implementation for a long time.
• 48% are 32 years old or younger. This is going to help the CL community to stay active for, I believe, at least another 20 years and perhaps even beyond that if the community can attract more programmers to this language. It is a beautiful language that is a joy to program in, so I do wonder why it isn't more popular.
• 31% are from the US. Countries like China, India, Netherlands, Poland, etc. have less than 3% respondents to the survey.
Incidentally, a bunch of us from Freenode IRC are doing a Common Lisp Programming Challenge this month. The objective is to help beginners get started with learning the language while being a part of a community. You don't have to join Freenode IRC to join the challenge. If you are interested in participating in it, please visit https://github.com/spxy/clpc to participate in the challenge.
CL must have some unique appeal that I'm missing. It's community seems to praise it's properties, but is rather quiet otherwise: Interesting talks, projects and companies are be eluding me, especially when compared to the above two Lisps.
It's a standard for the main Lisp language with multiple very different implementations, including commercial offerings.
For example at least two quantum computer companies use Common Lisp deep in their stuff.
Currently D-Wave is looking for a Lisp developer for their processor group:
https://jobs.lever.co/dwavesys/eca1f300-d90b-460f-9b7e-2660b...
CL most cited value: more featured repl, better live debugging
It's also the reason I could never really enjoy CL (or lisps in general): everybody basically ends up using their own dialect of Lisp with their own idiosyncrasies. Some people love the "loop" macro and use it everywhere, some others thing it's ugly and use the equally powerful but syntactically very different "do" construct instead. You can look at some lisp code and have no idea of what it does if you don't expand a few layers of macros first.
That can be true of any language of course, you can abuse overloading, references and macros in C++ if you want, but Lisp really pushes it to the limit in my experience.
Beyond that there's also the problem that the ecosystem is not quite as developed as other more mainstream scripting languages. It doesn't help that the community is split across half a dozen lisp/scheme implementations with often incompatible packages. Do you want to use SBCL? Chicken Scheme? Racket? Guile? Emacs lisp? CLISP? ECL?
I've not once expanded a macro in order to see what it does. The only reason I can think of that one would do that is to see how it works, but one also has to look at e.g. the definition of a function to see how that function works, and that should almost never be important. How are macros different? Just like functions, one often has to read the documentation to know how to use a macro, but I'm not sure how being a macro makes (loop for i from min to max do ...) harder to read than a function would be.
(loop repeat 10
for x = (random 100)
if (evenp x)
collect x into evens
else
collect x into odds
finally (return (values evens odds)))
This macro is actually fairly well designed, so you can guess what all of this does just by interpreting the names (assuming that you understand English well at least) but it's barely Lisp. Just figuring out what parts of this call are keywords and what part are just normal symbols is hard to figure out.(return ...) looks like a function call, but I don't think it is(?). Is collect a loop-ism or can I replace it by any function name? I think it's the former. Is "into" just here to make grammatical sense or are there other keywords I can use here? If `evens` and `odds` already exist as variable names outside of the loop, will they be used or is it a new local binding? If it is a local binding, how do I tell it to use some existing variable name instead?
Basically it's like printf format strings, it's a language within a language, and idiomatic Common Lisp is often full of that stuff in my experience.
That's to be expected with a DSL, isn't it? It's almost the definition.
But I think you're right. The point of a DSL is to change the language to something that you find more useful for what you're trying to do. The downside is that you've changed the language, and now people don't know what to expect unless they're very familiar with your DSL.
If you use the term "scripting language" as an indication, that Common Lisp is interpreted (it is often used in such context) - that is not true - language can't be interpreted, its implementation could - most Common Lisp implementations feature compilers to binary. The standard even provides you with functions compile and compile-file.
Regarding communities: you've mentioned three (or four) different programming languages. Only SBCL, CLISP and ECL are common lisp implementations and they share the same community - because they implement the same standard. It is as if you had said, that there are separate cython and python communities - each implementation has its merits, but users of both are usually part of the same python community. Similar comparison would be between clang and gcc programmers. Many many Common Lisp systems work well on different implementations of that programming language (some with compatibility layers, some are simply portable programs).
If you're just into functional programming and expressiveness, Clojure blows CL out of the water. Scheme also feels more cohesive, at least R(4,5)RS which is what I know.
The appeal of Common Lisp (to me) are CLOS, the condition/restart system, commercial portable GUI toolkits and specially the low level capabilities. Compared to it, Clojure just feels like a verbose APL.
Depending on the camp you are, Dylan, Factor and Julia are better Lisps than Scheme and Clojure, even if they are not s-expression based.
If you need to write a Very Large Lisp program for an industrial application with a lot of moving parts that has to run fast, you probably want Common Lisp.
[0] Racket is now compiled to the metal now too with the recent Chez compiler integration.
Here's a library I trust for linear algebra that uses BLAS and LAPACK. I haven't tried it on Windows.
https://github.com/rigetti/magicl
And of course there's always Maxima, the clone of Macsyma which was the grandfather of Mathematica:
The main problem I tended to have when starting projects in CL/Scheme was library support. Sure, I could wrap whatever libraries I needed in SWIG or the implementation's FFI, but that was work taken out of my all-too-small pool of time to work on something that wasn't the problem that interested me.
Clojure solves this problem by being hosted while also making a lot of the language changes I once dreamed of making to Scheme and Common Lisp.
https://github.com/atlas-engineer/nyxt
It's a web-browser heavily inspired by Emacs. It uses WebKitGTK+ as a backend, and they also have CL bindings for QtWebEngine, which uses code from Chromium, though I don't know if they have any plans to eventually support that as an alternate backend for Nyxt.
I don't mean the syntax, or the concept of macros (though I'm sure my understanding of macros is incomplete) but what I find is lacking in the documentation is how one actually might use lisp.
I read stories about "connecting to" a "running lisp" on a space probe and debugging in real time. Does that mean some lisp implementations listen on a tcp port? How does one actually connect to or disconnect from a repl? Is it just that when NASA launched their probe, someone went in on ssh and moved the process to the background with C-z?
How does one deploy a lisp application? Can I compile my code into an executable with, say, sbcl which is what everyone seems to use? Or am I forced to rsync all my source code to my server and get e.g. systemd to manually invoke an entry point?
The space probes are probably just a standard serial port (RS-232 style UART), with some radio protocol that has good error correction/stability. In amateur radio, FT-8 is a slow, reliable, long distance serial protocol often used for hobbyist DX (long distance goal) communication. So likely, yes, they have a minimal shell or REPL-style debugger, where they can at least query variables, and change the machine state. Most aerospace devices use single-user Real Time Operating Systems, which have guaranteed timing on programs running, but to a technician end-user, the feeling is similar to an old Unix system, with similar tool names.
You can deploy via compilation, with SBCL, or LLVM, etc. But I've mostly seen Lisp (well, I'm looking at Schemes, specifically) extending a compiled app. It's been pretty trivial connecting Racket to my compiled C functions, and I'll try Guile later, and for me it's mostly been a rapid-development tool to work with my WIP C library.
Under the dev-tools/editor section you'll see slime mentioned. It too has a manual: https://www.common-lisp.net/project/slime/doc/html/
It's common to use slime with emacs, but vim and atom work too. Slime includes a lisp program called swank which sets up a simple server that clients like emacs can open a socket to. In Common Lisp, "compile", "eval", "load", "break", etc. are built-in functions. Lisp programs are 'alive' and can be constructed or debugged and updated by compiling and executing bit by bit without having to suspend or restart the process, using the socket to communicate how to grow. Some examples are in this several part series you can take 10 mins to browse through: https://malisper.me/debugging-lisp-part-1-recompilation/ Going beyond that into say developing a full application with version pinning of dependencies and tests is documented in books/in pieces on the web (CL cookbook has a lot).
But manuals tell a lot too. Under SBCL's Saving a Core Image, you can see a standalone executable can be made with save-lisp-and-die. But you can also load things with --script if you want a python or node like experience.
Let me illustrate:
Suppose I want to compile my lisp code into an executable for easy deployment. My first step is opening the SBCL manual and reading the entire section on the compiler. There's nothing in there about how to actually invoke the compiler. Maybe there's a command line option. Read section 3 and find the "saving a core image" section. It has lots of verbiage about saving state to disk so that you can restart the program in the same state.
But I don't want to restart in whatever garbled development state I'm currently in. I want the program to start in the initial state and progress normally, the way a program in just about any other language would naturally execute. I want execution to begin at the entry point (does Lisp even have "entry points"? There's another 5 hours of wasted time trying to figure that one out) and progress naturally like it does in literally any other language I can think of. By saving the current state how do I know I'm not introducing bugs due to some variable holding inadvertent state when I save-and-die?
Okay so now I'm down the rabbit hole of stackoverflow and personal websites from random PhD computer science students at Carnegie Mellon from 2001 and about now is when I usually get frustrated, say "fuck it", and move on to a language like C# that actually has good documentation with copious examples (not to mention a library for just about everything), has an execution model that's actually easy to understand, and move on with my life.
I say this as an aerospace engineer: I'm a smart guy but Lisp must be beyond my reach as a mere mortal without a computer science degree. I went through most of the Gigamonkeys book and while I can write a mean LOOP macro I can't actually do anything useful with lisp. The documentation is too confusing and too fragmented.
I want to like Lisp but it fights me every step of the way.
Here is a real example from a real commercial project:
Makefile: https://github.com/rigetti/quilc/blob/master/Makefile#L72
Build script: https://github.com/rigetti/quilc/blob/master/build-app.lisp
Everything you’ve seemed to use are completely free and open source solutions. Common Lisp has at least two major commercial options with excellent documentation which you’re looking for: LispWorks and Allegro CL.
I hate this kind of wording because it makes it seem that Lisp is mysterious, or super difficult, or requires a ton of unlearning, or has no good (and free) learning material (you knock it but I enjoy Steele's 30 year old cltl2 mirrored on a CMU page), or is only for impractical purposes and CS-guilded programmers. I don't believe any of that, there are plenty of examples to the contrary. In contrast your own difficulties are puzzling. I hesitate to suggest reading, watching, or doing anything else, though things come to mind, simply to avoid wasting your time or money further if you took me up on any of it, as it might all be useless.
I'm not asking for Lisp to change. I'm explaining why Lisp is hard to learn.
>I hate this kind of wording because it makes it seem that Lisp is mysterious [...] or requires a ton of unlearning
In my experience these things are 110% true. Even ASDF uses strange terminology completely divorced from modern usage. What are systems and modules, and how do they map to what every other language calls a package or a library? I have no idea. The "Getting Started with ASDF" page that was the top hit on Google works through an example where they define a Cow System that has legs, tail, head, etc. That's the usual example when talking about class inheritance... So are systems classes? What about CLOS?
How the fuck do I get packaging in lisp?
Again, here is where I usually give up.
>In contrast your own difficulties are puzzling.
Okay, well they're still the difficulties I'm hitting.
I see lots of puzzlement on HN and elsewhere as to why Lisp isn't more popular than it is, and I honestly believe this is partly why. I have a busy job and soon to be a second child; I could spend my time trawling through powerpoint slides from MIT courses that took place in 2008 trying to find the answers, or I could brave the extremely caustic world of stackoverflow (no thanks, I deal with enough condescension already), or I could just give up and pick a different language and get up to speed faster and with less frustration.
>I guess I don't know what to say other than if you really want to learn Lisp
I guess I did want to learn Lisp, until I actually started trying to use it. The language itself seems awesome but the ecosystem around it, including the onboarding experience for non-graybeards, is pretty bad.
It is not hard to learn in general, there are too many counterexamples of people of all sorts and skills learning it without these issues you are having, learning it as their first, learning it later in their careers... (CL is big, I'll give you that, but each piece can be chewed one at a time and does not seem to be individually that difficult.) So I can hypothesize why it's hard to learn for you. My first guess is still that you aren't meeting Lisp in its own terms and are trying to make Lisp fit your mental model of some other language and its ecosystem. This isn't going to work, and the failure mode (if I'm right) has nothing to do with Lisp but with biases in general heuristics of learning.
You don't need to "unlearn" the way you're used to doing things, but you do need to separate yourself from it for a bit until you actually grasp the Lisp (and its ecosystem's) way(s) and can then see the connections, tenuous and non-existent as some may be. I'll risk raising some of those connections below, but really, things need to be understood on their own terms first or you wind up with misconceptions. (I've seen it multiple times with Java/Python programmers getting confused at the other's "import" statement.)
> strange terminology
It's not Lisp's fault that it's old. Being old means it will have terminology that may be alien to what we have today with nothing today being a perfect fit, or alternatively sometimes it expresses mostly what we say today in a different way. (And when you talk about concepts, not just pure language features, you run into incommensurability. See https://dreamsongs.com/Files/Incommensurability.pdf for an example with Mixins.)
CLOS for example has these things called "slots" which are more or less "fields" or "class/instance variables" in later OOP languages. But it's best to think of them as CLOS slots, so that you don't bring along any (mis)conceptions from other languages. It's sometimes amusing how different other OOP systems are given CLOS was the first to be part of an ANSI standard.
> that took place in 2008
I rather like that I can often find things decades old about Lisp and they are still relevant. Systems are at least as early as the Lisp Machine (1979). Perhaps it's worth going to the original description there? I also sort of like this history diving, even if modern sources obsolete the history in every way that matters. But here is the Lisp Machine manual on the topic: https://hanshuebner.github.io/lmman/maksys.xml "The way it works is that you define a set of files to be a system, using the defsystem special form, described below."
Is that unclear? Systems are first and foremost sets of files. Systems also let you define relations between files, primarily which files depend on which other files, as further sentences reveal.
If you're talking about this page as the first result: https://common-lisp.net/~mmommer/asdf-howto.shtml I agree it's an awful guide. I've never seen it before, it's a shame it's the #1 result. You'd be best served by ignoring it. Systems have nothing to do with CLOS, I assume that guide started trying to use animal parts as a way to elucidate dependencies. (A tail doesn't actually depend on legs though?)
I don't recall how I learned systems, probably because a mix of ASDF's manual (https://common-lisp.net/project/asdf/), this best practices guide linked from ASDF's home page (https://gitlab.common-lisp.net/asdf/asdf/blob/master/doc/bes...), just looking at example asd files of popular libraries and applications (https://github.com/CodyReichert/awesome-cl), a short ebook I occasionally shill (https://www.darkchestnut.com/book-common-lisp-application-de...), and just actually writing enough lisp and making my own library, were in part or all together enough. When you're actually writing software, you can just incrementally compile and load your files (or just eval chunks you've selected with the editor), or if you made a bunch of changes across the whole project then you can just reload your system (if you've defined it) and have everything recompiled and reloaded for you.
It's worth noting that systems are not part of the ANSI Lisp standard, though. Just as Maven is not part of Java. If you jump straight to Maven without first understanding how to create a Java program with multiple files using javac and jars, you might have a hard time later. Lord knows plenty of people get by relatively fine skipping around though (and might not even touch Maven directly, just do everything from an IDE); you can do this with Lisp too, but you seem to want to understand things more fundamentally.
Probably what you need to understand most is the core function "load" (http://www.lispworks.com/documentation/HyperSpec/Body/f_load...). After that you probably want to know about packages (which are akin to namespaces -- bags of symbols, if you already know what 'symbol' means in the CL context). You may wish to know about the "modules" mini-feature enough to know it's deprecated and doesn't really provide anything like what you think a module system should, so no one uses it, and that this mini-feature is independent from something else you might find rarely mentioned in ASDF that is unhelpfully called a 'module'.
> packaging in lisp?
Lisp itself doesn't have a notion of "packaging" in the meaning I'm inferring from you, so your question is wrong on its outset. It just has things like compile-file and load. If you like, you can loosely refer to a directory of files you load one by one as a "package" or a "library". You can define a system for those files with ASDF, and treat "loading the system" as something like "loading the library". When you want to get other "libraries" (directories of files -- just like python eggs or java jars, but lisp libs aren't compressed into zips) from the internet, or publish your own, the community standard is https://www.quicklisp.org/beta/
Sorry if this is just more unhelpful text, I can feel your frustration even if I don't fully understand it. I do agree that being alien is a detriment to Lisp's popularity, but that's not going to change. You might find some leverage by working at CL from the less alien Clojure as a starting point. I always thought this two part talk on Clojure for Java Programmers was really good, but the last person I sent it to dozed off watching it, so your results may vary: https://www.youtube.com/watch?v=P76Vbsk_3J0
I started in Lisp in around the year 2000. In 2002, I released a program called Meta-CVS: a wrapper version control system based on CVS storage, and using the cvs program under the hood. With Meta-CVS, you could store permissions, symbolic links and the directory structure itself as a versioned object. Plus do things like imports of code snapshots with automatic rename detection.
Meta-CVS uses Makefile to build. Every .fasl depeneds on the corresponding .lisp and is recompiled if it changes. The CLISP memory image depends on the .fasls and so on.
Using Lisp like C in this manner is just fine.
2) LOAD your code
3) specify a toplevel function (aka 'entry point') and let it be executable -> SAVE-LISP-AND-DIE
Result: a standalone executables which starts up with the toplevel function you have specified
Right; the thing to is to start a completely new image, and the only thing you do in this image is load all of your compiled files, and then call the image-saving function.
This was pretty obvious to me, coming from a C background.
My first Lisp programs used Makefiles to do this stuff.
You don't want to sit there and making deployed executables manually out of your dirty hacking session, of course.
> I want execution to begin at the entry point
Common Lisp implementations typically offer some image saving function, which has an argument for specifying something to be evaluated when that image is restarted, or a function to be called or some such.
This general area is called "application delivery": you have to investigate the ways that your Lisp implementation offers application delivery. Saving an image might not be the only way; there may be a way to create an executable which isn't a saved image. In some Lisps, the hash-bang mechanism is supported, and that is appropriate in some situations. Some Lisps can produce shared library, even.