We've also been using Lisp in production. It has gone wonderfully, and has allowed some of the most simultaneously maintainable, resilient, and efficient code I've seen in my career. It's also attractive differentiator to some programmers who don't want to drone away writing bulk-Java day-in and day-out.
A key to running Lisp in production is to step away from thinking of it as a lone-wolf bionic-suit hacker language, and to invest in developing a style guide, code review guidelines, CI/CD, and a culture of training new programmers to write Lisp. I've found that you typically don't have to hire Lisp specialists. As long as you find good programmers, they pick up Lisp just fine in just a few short weeks.
The sibling comments are right though: Lisp's reputation is unfortunately affected by so, so many myths that it actually stunts the ecosystem in certain ways. The most rampant myth these days is that (somehow) macros automatically imply doom of a codebase after a certain size or contributor count. Classic myths from decades ago, like "Lisp is interpreted and slow", still echo from time to time too. Lisp's extensive, half-century history is a strength but also clearly a (social) weakness.
A lot of myths come from good-intentioned speculation of the supposed consequences of certain features or aspects of Lisp, and not from actual experience using it.
This has been exactly my experience too. It's easy to bring good programmers up to speed in Lisp. It's sometimes harder to bring existing Lisp programmers onto a team. Let me explain: Some Lisp programmers (not the majority, but some) learned it on their own and it became their personal hobby-project language because it's so powerful. When those programmers join a team they bring bad habits with them. Bad habits like using lists for every data structure, overusing reader macros, not using packages properly, writing their own functions for things covered by well-tested cross-platform quicklisp libraries, etc.
Programming in Lisp is very different than software engineering in Lisp. Of course that's true in any language, but Lisp has a lot more "shoot your team in the foot" possibilities than C, and you absolutely need to learn to avoid those patterns or formally communicate your use of them in order to make Lisp effective on a software engineering team. Rather than depending on the language itself to enforce good software engineering discipline, with Lisp you must create out-of-band agreements with your team about how to write good software. This is not a bad thing; it's something all SWE teams should do anyway. But Lisp is especially intolerant of neglecting this aspect of SWE.
> Lisp has a lot more "shoot your team in the foot" possibilities than C, and you absolutely need to learn to avoid those patterns or formally communicate your use of them in order to make Lisp effective on a software engineering team.
I love Lisp for its adventurous and fun nature, but the above statement is a huge negative for real engineering work on a team. Any time you can rely on your tools or language prevent these types of issues, that's a win. This became especially evident to me when my team started using Rust. Code reviews are now almost purely about logic and design.
You don't shoot yourself in the foot in the same way one does in C. With carelessness, you more... suffocate yourself with your own towers of (probably useless) abstractions. It's like having a power drill when all you knew was a screw driver... and then drilling holes and driving screws every chance you get without regard to a larger structure.
Unlike C, the powerful (and safe) language features are a boon to software engineering projects, as long as you're doing was dreamcompiler said: software engineering and not "just programming".
I disagree with the thesis that the more restrictive one is, the better it is for software engineering. We've empirically disproved this time and time again with every supposedly "simple" language evolving way, way past its original design goals. Python, Go, and even Scheme are great examples.
That's a great way to put it. With C you can build a car. With Lisp you can build a better car but it's also very tempting to build a car factory, and a motor factory to supply that, and an iron ore mine to supply the motor factory, and just for grins let's go ahead and reinvent physics in a way that suits our purposes and hey, faster-than-light spaceships are probably a good idea too so let's build those, and pretty soon you've completely forgotten about the car.
Lisp: With great power comes great responsibility.
I am not trying to extol the virtues of C. I find C a low bar to improve upon, and I'd prefer Common Lisp over it in many cases.
What I am talking about is having to rely on people to do the "right" things when your toolset could be enforcing many of those things. We've empirically shown time and time again that people are poor at consistently avoiding pitfalls. This is especially true as the size and complexity of a project grows.
Lol, with the new JIT compilers and TruffleRuby, Ruby is blowing Python out of the water performance-wise. TruffleRuby approaching Nodejs speed for some tasks.
But yes, CL is fast. Faster than any other dynamic language, approaching Java speed (and Java is shockingly quick considering it has a GC).
It's always cool when we can achieve a speed up in something, but I fear that we may have reached the point of Ruby becoming mostly irrelevant to the larger market. Python, thanks mainly to it's data science libraries, has taken it's place as the go to non-JavaScript scripting language. Unless Ruby comes up with some killer feature like it had with Ruby-on-Rails back in the day, I doubt that the speed up of Ruby will be what revives it for most people.
All of that said, I would love for Ruby to usurp Python from it's thrown!
Python did a good job offsetting speed issues by rewriting key parts of libraries in C (or maybe C++/fortran in some spots). I don't know if the same effort ever went into key Ruby libraries.
The decline of Lush [0] as a popular data-science language saddens me.
One could use it as a dynamically typed interactive language with nice support for nd array manipulation, excellent support for calling C functions. Once satisfied with correctness of the implementation one could then compile it down to a statically typed C for speed. It ran circles around byte compiled Python in speed. Two of Python's relative advantages in the data-science domain were (i) nicer array manipulation syntax and (ii) one could build the non data-sciency part of the application in Python as well thus avoiding a proliferation of tooling and languages necessary.
Regarding Ruby, even TCL was faster than non JITed Ruby. That was funny because TCL used to be considered the slowest possible runtime (among professionally used runtimes)
I have used C, Java and even Perl extensively for the same "one-off" (like small command-line tools) and "everyday" kind of programming. But it's in those "everyday" kind of programming that I have found most value. The reason is that I often end up doing the same sort of tasks over and over again. As such, I don't want to waste time doing something trivial just because it has to be done so often, but to do something more productive.
For some languages, I could not find much of a reason to use them for such tasks. When in Java I used StringBuilder instead of simply concatenating the values. If I had to add something to the existing string in C, I used memcpy and memset. It's easy enough to understand why. So why would I do the same thing again in Lisp? For the same reasons I did in C?
Personally, it used to be the biggest issues in tackling scripting tasks in Lisp in my experience was slow startup (mind you, we're talking about running from 4200 rpm spinning rust). There are people successfully using it for such kind of work, and generally it used to be common in environments with more Lisp support.
These days my biggest issue is that I kind of lost the need for anything more than Bash for one-off tools, and I do it rarely enough that the incremental benefit faces big hurdle of dealing with development-antagonistic environment (mac)
For building optimizing compilers for quantum computers.
The biggest hurdle has been difficulties with deployment. Open-source Lisp implementations mostly[1] only let you build an executable, and not things like a C ABI-compatible shared library. Commercial Lisp implementations are a lot better in this regard.
Even if your OK with building an executable, there are limited options in terms of "enterprise integration", especially in the arena of databases and RPC. Google only very recently released support for gRPC [2], for example, and it's not a first-class citizen in Google's gRPC offering. Most hobbyist Lisp hackers don't exactly care to build (and more importantly maintain) a bunch of open source stuff for enterprise use.
[1] There is a Lisp implementation called "ECL" that compiles Lisp to C, but it's lacking in many other dimensions.
Cool! I used CL for the same purposes in my PhD almost a decade ago. Interesting to see that others independently have been gravitating towards CL.
I had a top-level pattern language with a dataflow-like visual representation, using the LispWorks UI lib to make the editor. That pattern language compiled down to a Measurement Calculus representation (one-way QC, so not the usual circuit model) in s-expr form, which I could both execute with my QVM and do optimizing transformations on. I had a CL QVM was initially CL, but it was quickly replaced with a C + OpenMP version using the same s-expr input.
Parallelization and SIMD are pretty easy for numerical code in CL now; I don't think this was the case 10 years ago. LPARALLEL is a nice small library for core-parallelism, and CL-MPI is good for MPI/cluster parallelism. This QVM [1], a pure/density-state simulator, can use either.
How do you convince good programmers to spend their life writing lisp? It's very hard to find lisp work after your company, so it kind of wasted years.
The same way I convince them to learn an employer's large code base that will be useless to them after they leave too: by paying them.
That's a real, non-facetious answer. Another facet to the answer is that many people see value in learning a different language to help give them perspective on the existing ones they already know.
I generally don't consider it a net loss to ever learn a new language.
For many journeymen developers, the choice of programming language is important. There are many, many companies out there that do look for people with N years of experience with language X and not every developer out there is in a place or at a skill level where they can afford to be picky (the average HN developer isn't representative of this population).
I love Common Lisp. But I don't think you can look at a list of features and decide if it's a good choice to use or if those features are now "covered" by more recent languages. Not all REPLs (for example) are born equal, and recent is rarely a good thing when picking a programming language. I don't always use Common Lisp, but when I do, I enjoy the combination, depth and maturity of many attractive features that have only recently been introduced elsewhere (like poweful macros or the ability to compile into a running program). Also, I think not knowing Lisp is in a way like not knowing any C. Regardless of what you use at work, there are huge parts of the literature and discussion about programming that are closed to you.
It's cool to see an organization working with CL in production. I totally understand why more companies don't follow (and honestly I'm not sure I'd want to coexist in a CL codebase with more than a few programmers) but it's still encouraging.
Perhaps it's because of typing. Personally I find that structural insights on code from static analysis to be just as important if not more than local readability. I also generally find that it's the complexity of program strategy that impairs local readability more than syntax or style.
Common Lisp has type declarations and I think on a big code base, I would want to declare most if not all of my function types.
And the types are not just for information: the compilers can and do optimise heavily if you ask for it with `(optimise 3)`! You can get nearly as fast as C.
Without a library like Coalton, the type system built into Lisp is pretty limited. (It feels pretty similar to C's.) So you can't[1] declare types like "list of foo" or "function that takes any type and returns the same type".
[1] There is something called a SATISFIES type which lets you turn any globally defined predicate function into a type, but I don't find that it's used widely in practice, because the compiler can't reason about it.
It is, because libraries like Coalton don't give you an expressive type system "for free", you also have to agree to write your code in a certain way. As such, it's completely reasonable for Lispers to opt out of using such opinionated libraries, and instead using only what's provided by the standard.
If you do use a library like Coalton, then you get a type system pretty close to Haskell's.
Aw yes, the hellscape that will exist when someone's pet micro-service losses it's creator as they leave for another org. They decided to write it in a language that nobody else on the team is familiar with, and now that decision has come home to roost.
I hear this a lot but my experience tells me otherwise.
For example, I worked on a Clojure project that would leverage this supposed “10x” power of lisp. Despite hiring the even key Clojure contributors, this hypothesis was falsified. The project went from around 35 to over 400 people and it is moving at a the speed of glacial ice.
Once you have a project with more than a few people a better language does not have much impact: it is all dominated by people factors and how to fit the project into its larger context.
Any "10x argument" is just lazy thinking. 'Productivity' is governed by so many factors, its just unrealistic that 'choice of programming language' would have such an enormous effect (unless you benchmark CL against let's say COBOL).
On a fun note: The old guard of Common Lisp (like Norvig IIRC) was very fond of Python when it hit mainstream because for them it had a whole lot of the feature set that lisp had which other popular languages lacked.
[disclaimer: I am a die-hard Lisp and Clojure fan but the other fans just make me cringe at times]
It's interesting, lisps, [o|oca]ml .. have often both, but somehow this practice never went mainstream.. even js got huge influx of money to push vm super fast but no native code practices.
I agree. And I think that the constant BS claims of certain Lisp advocates actually damages the Lisp community. Especially the silly “I am smarter because I use Lisp” claims you often see in Lisp articles. My answer is always: OK great. Why don’t you instead first build some impressive stuff in Lisp and then show us how Lisp made it possible for you to build it 10x faster. Then you might actually make people believe you. Especially given that pretty much all successful software out there is written in (or run on top of) C/C++.
when i wrote this reply i didn't expect it to generate such a discussion. it was meant as a sort of smart-arsy opposite side to the same coin of which the other side was parent's claim that lisp is not suitable for large teams. the claim that lisp is not suitable for large teams seems ridiculous to me, especially given the prevalence of javascript and python in industry. surely lisp cannot be worse in large teams than these languages. usually people mention type safety in support of these claims (which again makes no sense given the prevalence of js and python), but this point is even more mute now given coalton's existence which allows you to have haskell-like type safety in common lisp - https://coalton-lang.github.io/
on the other hand i think people can be more productive in lisp provided certain criteria are met: they are motivated to solve the problem at hand; and that they enjoy and are capable to use the tooling that is offered in lisp to its full extent. but this is not surprising because in order to understand lisp to this extent you have to understand far more about computing than just knowing lisp syntax, which is trivial btw
Look I know Lisp quite well, have written more than one dialect of Lisp for fun, and have 25+ years of professional software development experience behind me. I don’t think there is anything you need to somehow understand better about “computing” to use Lisp. But you are welcome to convince me otherwise. Do you have any concrete examples?
> I don’t think there is anything you need to somehow understand better about “computing” to use Lisp
I am not saying that at all. If anything I said the opposite of that. I think, given how simple Lisp's syntax is, being able to write/use Lisp is almost trivial. However being able to use Lisp is a way that has given it an almost mythical status (one being discussed in this thread is the so-called "x10 programmer") requires far more than just being able to write Lisp
Can you give examples? I see a lot of hype but no actuals. Becoming super productive in any language requires a lot more skills than just learning the syntax and semantics of a language. So why do you think Lisp is different? It would help if you could point at real world projects that demonstrate your claims.
i can't tell you because the *lisp-king-lizard* will come and eat me if i divulge secrets
EDIT: see the problem i have with your post is its tone and refusal to read what i actually wrote. if you read it properly i am not saying anything different to what you seem to be saying: if you are a good programmer you can be productive in any language, including lisp. if you are a crappy programmer, knowing how to write lisp is not going to save you. knowing how to write lisp is trivial. even implementing some (minimal) dialect of lisp is not too difficult
on the other hand, i think that repl-driven development that is available to many (all?) common lisp implementations is unmatched in any language, and i think that this is unique to common lisp. please see the post by mikelevins in this thread that details this process. i think this can be a great productivity booster for production as well as exploratory programming. in any event i enjoy it a lot
If you think about GNU Emacs, that one is written in C and Emacs Lisp. The original one was written in TECO. I'm using two other ones, which are written in Lisp.
To confess, I am probably, on a good day, 0.8x programmer. (I have known a handful of 10x programmers. And more than a few 0.1x programmers.)
My first big project was in FORTRAN II. The way that IF statements worked was really horrific, what with three statement labels. Next up was a massive project in Sigma5 assembler with interrupt driven tasks. Once we implemented co-routines, co-operative inter-process communication was a breeze, with very few multi-thread errors. I cringe when I see folks struggling with async-await hell. Prior to go, the only language that I saw that did co-routines well was Bliss-36.
Later I did a lot of C (pre-web). When I picked up C++, I ended up with fewer crashes, as I found it easier to deal with pointers to objects.
I came to Lisp later on, and am still working with it. It is a lot better than other languages for me in several ways. First, it is quite expressive. Secondly, with a slime, it is trivial to debug using break statements, ability to instantly navigate to the source of a function, be it yours or deep in the heart of e.g. SBCL. I use Lisp exclusively now (with an embarrassing amount of bash mixed in), but not because it is 10x for me. I am likely several X more productive, but in part due to the debug ability plus the repl.
Also, sbcl is really fast, even if you don't resort to hackish tricks like was done for sbcl to intimidate other languages in the mandelbrot benchmark game. Or log4cl compared with the speed of log4j.
Where some real leverage comes in with Lisp is the ability to express things that are significantly more difficult in other languages. There are things done in Lisp that are just plain impractical in other languages.
But there are some things that the programs are just about as annoying as in any other language. Look at the code dealing with http in either of the libraries drakma or dexador. Lisp ain't much help making that awful protocol go away.
And often in larger projects, minor advantages of a language compound to end up with a 2x or better result.
So this argument about a language being a miracle productivity tool is a pretty old one. I had a boss, a PhD fellow much smarter than I claim that higher-level assembler languages would make writing an operating system trivially easy. I was a bit suspicious of that then, and am quite certain of it now.
hi. thanks for sharing your experience. i just saw in your profile that your domain is security. if i may ask, do you have experience with lisp in this field, particularly as far as networking and encryption is concerned?
as regards this 10x business, i actually wasn't being very serious. it was just a playful response to the parent's claim that lisp is not suitable for large teams
No, oddly my security work (mostly application security and a bit of compliance work) is not with Lisp. Although I do use Lisp to generate my documentation.
I have toyed with the idea of using Lisp to take apart binaries.
Also, Lisp wouldn't be very good with encryption, as it doesn't do constant time very well.
Largely because of myths surrounding it, for example parenthesis syntax and lack of editor support. With paredit, you get meta level direct AST manipulation support in emacs that is still light years ahead of any programming IDE out there. I think the other fear factor is you have to think a lot more about how to approach the problem when writing Common Lisp and it requires a more complete engineer due to a smaller library ecosystem. Usually there is one and sometimes two libraries for doing X and if not you’re up for making a library yourself.
I’m attaching an example of how quickly you can write TLS 1.3 by a single person in Common Lisp. At the time I wrote this library most websites still struggled with TLS 1.3 support. The point is that most software creators don’t have the breath and depth of knowledge required to be proficient in LISP if they only posses siloed domain knowledge.
> With paredit, you get meta level direct AST manipulation support in emacs that is still light years ahead of any programming IDE out there.
Do you happen to know of a video or article with visual examples that demonstrates this? I always hear about these things with Common Lisp, but I have personally never seen it. I’d love to understand how this works or enables people.
That’s helpful. I’ll read it more in depth when I’m off mobile as that site is hard to read on mobile.
Although, I think there’s still something missing between those demonstrations and the quoted claims.
I have never used Paredit when doing Scheme or Racket, so maybe I should just hunker down with it at some point (I have looked into it before). I don’t use Emacs (tried it a few times), but there are several Paredit-based VSCode extensions.
Paredit is the editor part, but then there is also SLIME REPL.
In lisp, unlike in other programming languages, you don't start writing your code with a blank slate and an empty source file.
A common approach is to start with an initial core. The idea is that all programs start the same, with an initial core, that contains runtime and standard library. You can test things out in a REPL, that you run side by side with a text editor. As you work things out in REPL, you can start moving them to the text file and the program starts taking form and shape. It's a much more exploration driven design and with fast structure editing of paredit you can really transplant or reorganize pieces of code really quickly. The idea is to grow the program from the initial core into something else inside-out style. It's akin to being dropped into a running program, and modifying it as it is running but that is not possible with most languages easily and as interactively as in Common Lisp for example.
With SLIME the REPL and text editor integration, you can for example write a buggy function, test it in REPL and find out about the error. Modify it in the text editor, press Ctrl-c twice, and the function is hot reloaded on the fly. No reloads, no re-imports, no-caching, no program restarts. Next time the function is called, it is replaced with a new stuff you just wrote. It really is pretty magical. It just works, and works for classes, objects, meta classes, functions, variables, etc.
The language is unlike other languages, because it offers object introspection (often mistakenly referred to as reflection) and object intercession; introspection and intercession combined give you a true reflection. It is the latter technique that supports all of the above, for an imho superior development experience. It really just works, and it works marvelously well. No yak shaving for hours on end trying to get some dependency chain to work, compiler errors, package version mismatches, etc. No need for build team, no need for testing/qa team, no need for most of your usual dev overhead we are so used to these days :)
You could start with a copy of the book „the land of Lisp” or „practical common Lisp”
People seem to recommend portacle https://portacle.github.io/ for a first dev environment but I usually set everything up myself. Portacle seems to have all the essentials. You can follow SLIME installation instructions from the quicklisp page of portacle doesn’t come with it.
Next Advent of Code, grab yourself a download of Portacle and see how far you can get with Lisp.
By day 7 you should have a feel for what people mean when they say you are directly editing the AST.
Basically: there is the same amount of friction to moving constructs around at a high level as there is at a low level, and this is due to Lisp’s uniform syntax, and paredit leverages this a lot.
Contrast this to a language like Java, where the friction between modifying a single expression and modifying class-level interactions are totally different, syntactically. Now you find yourself leaning on highly specific IDE-level support or Lombok for things like setting up Builders for every POJO, to get around these constraints.
From a Lisper’s perspective, these syntactic constraints are unnecessary, and should at most require a library that you can trivially port to any editor. Which is exactly what paredit achieves.
I have used Scheme and Racket a fair amount and know bits of Common Lisp.
What I don’t understand is what I stated and what I quoted.
Without seeing it demonstrated, I just don’t understand the quoted claims. When I’ve done Scheme and Racket, I never really needed to be copying and moving ASTs (i.e., parenthetic groups) all over the place. Maybe that’s just me and my style, for better or worse.
I think "structural editing" is a better way to talk about it. You manipulate code as units of S-expressions. You don't type parentheses so much as you create and modify (trees of) S-expressions. So things like unbalanced parentheses or improperly indented forms are not possible since there's no way to create them in the first place.
In a somewhat vague sense, the "units of editing" are not characters.
There are some videos on YouTube demonstrating ParEdit and SLIME.
That’s fine, but I don’t see where one gets "light years ahead of any programming IDE out there" from that.
I like Lisps/Schemes as much as the next person, but other languages don’t have parentheses to deal with, so by that same token, you’re getting that for free, such as an ML like F#.
There isn’t a single language IDE that I know of outside of Lisp that allows you to hoist a sub block of a loop (a sub tree in the AST) and remove the parent of that code and paste the hoisted expression while simultaneously removing the loop construction with a single key. Please show me an IDE like that and I will buy it immediately. Paredit is not about parenthesis editing and matching despite its name.
with lisp structural edditing you are editing blocks of code, as opposed to characters. in fact it is the use of s-expressions that makes this possible. here is a simple example. immagine you have a list, two elements just outside it, and your cursor is just after the second element:
Python: [x,y,z] 1,2
Lisp: '(x y z) 1 2
and lets say you want everything in the list st
Python: [x,y,z,1,2]
Lisp: '(x y z 1 2)
in python it would take me about 5 keystrokes to achieve that, while with paredit in lisp it takes 2. this is just a very simple example of the most basic paredit operation. extending this approach to your whole source file and treating whole blocks of code similarly to the above examlle i find really handy
I think the paredit stuff is a bit overblown but apart from managing parens for you, another simple example is editing single expressions. e.g. in Java you might have a line: "int a = blah.bar(something, thing, whatever);" If you realize you need to actually pass "whatever" first, not last, unless you know an IDE shortcut that can make the edit for you, you're going to have to type stuff. I would probably just move my cursor to the start, type "whatever, ", move my cursor to the comma after "thing" and highlight to the end then delete. If "whatever" was a longer variable, or even more interestingly an entire sub-function call like "whatever(x, y, z)", I might instead highlight it all, cut, backspace the comma, move cursor to the start, paste, type a comma. Moving the cursor to the start might be character by character, or using the operating system wide ctrl+left/right to move in 'word' chunks, or possibly it's faster to use the 'home' key first or god forbid the mouse. Oh no, I might miss a comma or somehow mess up a paren/semicolon or typo a name?! Whatever, it's rare for me, and for most mistakes I'd get a red squiggly alerting me to it immediately. I like typing, and prefer most 'helpful' plugins get out of my way for most things, so such a process isn't that annoying to me.
But I do at least see there's a nicer process if you have something like paredit: you just move you cursor to the "whatever" (even if it's instead "whatever(a,b,c)") and a command will move it to the left/right/etc. and fix up anything that needs fixing up. In Lisp though the base syntax is so simple and uniform that there's not usually much needing "fixing up" -- there's no pesky commas to deal with for instance, and having the opening paren come in front of the function name instead of after simplifies a lot of things. The worst is adding/removing/moving a form that's at the end of a let binding, or sometimes introducing a let binding, or sometimes adding something to the end of a function that previously ended with ))).
I like to use vim (which does have paredit though I have it disabled) and just having the ability to jump between open/close parens by pressing "%" and to cut jumps as a whole, or the insides, without having to move my cursor character by character, is good enough for me. I still use some paredit-like commands in some instances like moving forms around or in those "worst case issues" I mentioned but I use them with these mappings: https://github.com/tpope/vim-sexp-mappings-for-regular-peopl...
There are more advanced things but how much I care about them varies; I don't tend to need them for Lisp, though every so often I'll miss something from Eclipse that I suspect not even emacs does (or does well). e.g. I know emacs can do a "templateized" completion just like a Java IDE where you type a function name and it completes it and inserts its required arguments as placeholder variables to later define/type over, I don't know though whether emacs can then let you place the cursor over each one in turn and with something as easy as 'ctrl+1' hoist that var to an assignment form just above (I did this all the time in Eclipse to avoid having to choose a name, type it, and type its correct type). (In Lisp it's complicated by needing to introduce a let binding if it doesn't exist or append to one if it does. It wouldn't surprise me if paredit can do this, it's just that I'm aware of some refactoring tools in Slime but they don't tend to approach what Eclipse or IntelliJ users expect even if in theory they could.)
1) Lisp acquired a reputation of being associated with AI, back when that was a bad thing, lots of government-funded "expert system" boondoggles and the like. It is not considered a general purpose language, despite being one.
2) Lisp is thought to have poor library support. Unlike Java or JavaScript, which have standard libraries for every task, Lisp is thought to lack this. Quicklisp helps, but it's not as comprehensive as Maven or npm.
3) Lisp is associated with a certain programmer type: highly intelligent, persnickety, only interested in solving interesting problems. Companies prefer programmers who have only a moderate amount of technical skill but who are diligent, who will take orders and get the job done without complaint.
4) Not many programmers actually know Lisp, because not many bother to learn it. If CS students are exposed to Lisp in college, they will complain about it and won't touch it again after passing required classes that use it. This means Lisp has a much smaller qualified candidate pool and it's much harder to hire Lisp programmers.
5) Software projects, especially enterprise software projects, are optimized to require lots of programmers each of whom develop one component without stepping on each other's toes. In the enterprise, not breaking existing things is more important than building new things rapidly. This is why OO languages like Java are so well loved... they help encapsulate programmers from each other as well as encapsulating units of functionality. Each programmer poses more risk in a small team where every programmer's responsibility is larger (and every programmer could theoretically rebuild the whole system themself given enough time) than in a large team where none of the programmers have a complete understanding of the system and everybody stays in their lane.
7) Larger programming teams are just more impressive. As a manager if you have 100 direct reports instead of 10, you are a bigger deal. You can command a bigger budget, which also makes you seem more important.
So the odds are pretty stacked against Lisp. It doesn't scale well to large teams, but it lets a small team get more done. The incentives in most software development reward large teams of programmers just barely smart enough to get the job done, not small surgical teams of wizardly Lisp hackers. So Lisp remains niche, perhaps rightly so.
To expand on this, JPL probably has 100 Lisp engineers because it has intricate astrophysics problems that warrant 100 Lisp engineers. Most companies will never have such difficult problems. They may think they can, but they cannot. They can have crappy problems, however, and crappy problems can tie up those engineers provided they have very little agency in solving the underlying problems that give rise to those crappy problems. And you have to be careful to manage them very adversarially to keep it that way because they will totally try to actually fix things without your knowledge or permission. Not always, though, sometimes they get stuck in a mesh of very nerdy concepts and then there's no risk.
This is yet another “non-Lisp programmers are not as smart as Lisp programmers” comment. Seriously? I know Lisp well and have implemented my own variations for fun. But I prefer other languages. Lisp has been over hyped for 50+ years and have still very little to show for it. The world runs 99.999% on non-Lisp code. So perhaps consider that there might be a reason why? Unless you actually want to suggest that 99.999% of developers out there are less intelligent than Lisp programmers? Really?
A console game generating $500 million+ in revenues, a high performance optimising compiler used in production, an embedded web server used by companies in the field, Android software used for warehouse management, commercial 3D engines etc. And much more I can’t remember right now. Why?
So what have you implemented in your magical 10x language? I told you some of what I have done not using Lisp. Here is your chance to brag about all the cool production stuff you have written in Lisp. Let me get my popcorn. I am waiting :)
I don't disagree with you about whether Lisp magically makes people more productive: It doesn't. But you've asked for this kind of example a few times in the evident expectation that no one can supply an answer, and I can, so, just so that there is such an answer in evidence, here's mine.
I won't distinguish between projects that I wrote 100 percent myself, and ones where I was a contributor on a team. I include examples of both. Similarly, I won't distinguish between pure Lisp projects and ones where Lisp was one important tool among several, or between projects that I conceived from the start and ones where I joined someone else's.
- a knowledge-based application compatibility testing system used in production by Apple to identify and report thousands of compatibility bugs in its system software
- an experimental operating system for an Apple mobile device
- a network security appliance acquired and shipped by Cisco
- a direct-manipulation-based rapid application-development system
- an embedded system controlling a forensic fingerprint-scanning device
- a consumer-focused simple list-management database
- a commercial graph database
- a framework and compiler for building mobile simulation games
- a knowledge-based control system for laser-sintering manufacturing machines
- a strategy and control system for networks of real-time sensing devices
I've omitted hobby projects and things I built only for my own use. All those above were for employers, clients, or direct sales to customers.
Although, like you, I don't believe that Lisp magically transforms anyone into a 10x programmer, I have actually been a 10x programmer (according to DVCS statistics or stakeholder reports) on some projects, but I've only managed to do that using Lisp.
To be fair, I have also been a 0.1x programmer, but never for very long. It's hard to be happy or to prosper in such a situation.
Again, I don't disagree with your main point. Lisp won't magically make someone amazing. I do think, though, that it's a powerful force multiplier for programmers who get along with it well, and that for certain people (myself among them) it's the best kind of tool.
I also don't think much of anything is proven by failing to find anyone who's done substantial work in Lisp, or who did things in Lisp that they couldn't do as easily without it, but if that did prove anything, then I guess I would be the disproof.
thank you for this! it is always so nice when someone uses 'argument from authority'[0] to pounce their preconceived notions onto everyone else, then someone else from even more authority proves them wrong. i also appreciated the following piece of honesty:
> I won't distinguish between projects that I wrote 100 percent myself, and ones where I was a contributor on a team. I include examples of both. Similarly, I won't distinguish between pure Lisp projects and ones where Lisp was one important tool among several, or between projects that I conceived from the start and ones where I joined someone else's.
on the other hand the person you are responding to claimed to have "implemented" a console game of great commercial success. this is somewhat disingenuous because at least according to the credits of said game, he was NOT the chief person behind its development. moreover, the one game i managed to find in which he was chief turned out to be a flop. in any event, this is still far more programming experience than i have right now, but since he likes games maybe he would appreciate knowing about the use of lisp in that domain and look up 'Game Oriented Assembly Lisp' [1]
being responsible for this 10x mess (in this thread) i want to once again explain that it was just a playful joke. the parent claimed that lisp is not useful for large teams and in response i wrote that if he employs lisp he will have no use of large teams. i think this was a funny throwback to the 10x myth. but then again tastes in humor vary more widely than preferences for computer languages!
anyway, i definitely do not think that people must use lisp, or that if they do they will magically be a super-dooper-programmer, or opposite: if they don't use lisp that they are somehow less worthy as programmers than lispers. i am definitely not a 10x programmer (nor do i try to be), but i really enjoy programming in lisp and i feel like i am more productive in it. however, what i think is important in my experience is that for quite a while i wanted to learn lisp but certain mistaken preconceived notions about it always diminished my motivation. so whenever i advocate use of lisp it is aimed at people who are of similar state of mind as i was then and i try to address those issues that held me back
yes you made some claims but i am a little bit skeptical :) tbh i don't think you have a handle on this subject at all. also i specifically asked you about your implementations of lisp and you mentioned everything except that. it's not interesting. as for me i work in machine learning and we are starting a project in which lisp is used as a sort of glue language between various components. i only wish more of the stack consisted of lisp components, but who knows maybe it will eventually :)
So you don't have any experience using Lisp on large scale projects. And the project you are starting now is only using Lisp as a glue language. Count me not surprised.
Doesn't saying stuff like this just contribute to your reasons 1-3 that boil down to perception issues, and not anything wrong fundamentally with the language itself or even its modern day practitioners? I don't disagree that Lisp doesn't scale in the sense that there's not enough Lisp programmers available to actually scale to such grand sizes of even 1000 developers right away, but as I'm sure you already know I want to say for the benefit of passersby that Common Lisp itself is object oriented, has namespaces and can support a modular or component style of development, its global memory model isn't too unlike that of the JVM prior to Java 9 (i.e. everything dynamically loaded and being introspectable and to some degree changeable (more effort in JVM)), it's been used for multi-million line projects (not sure how large the teams for those are/were though), and nothing of the recent microservices trend to scale in a different way is forbidden to Lisp...
Besides, it's not like enterprise companies that have 1000+ devs actually have a 1000+ size team with a single standup. No, things are divided into smaller teams of around 2-10 with maybe 6 being average.
I disagree somewhat with your reasons 3 and 5 and 7, having worked at an enterprise company with thousands of developers and been involved in hiring processes. Maybe I was just lucky and other enterprises are different? In my case, the implicit incentives might sometimes align in the direction you indicate, but explicitly, no, they don't. Hiring selects for stronger technical skills over weaker technical skills, interviewers prefer candidates who have a story of leadership/taking action/dealing with people socially (i.e. how do you handle such and such kind of a disagreement) over heads down and take orders and pretends there are no disagreements, no participation. Each engineer is pressured into career growth and expected to reach a certain role level after N years. Getting promoted to such a level typically involves taking on some sort of leadership role that impacts more than just your own team, and often more than one such role or a secondary role in another's project because things fall through. Despite encapsulation, things very often broke in the monolith (note only in development, production breakages were rare), and many new hires had to be trained to not sync every day if they wanted a more peaceful life. The teams that end up with a domineering management who allow no input from the development side typically don't last long because the developers switch teams (easy to do in an enterprise org where there are tons of teams with headcount every quarter) and with no team left area ownership will be dispersed. No manager has 100 direct reports. They might have 100+ indirect reports, but after a certain direct size, they have to become a higher level manager. They may still retain a couple ICs as direct reports but most of their directs change into a small number of other managers or directors, in classic org chart hierarchy.
Because you need to find those 10 lisp programmers. The ratio of mediocre Java to good lisp programmers is probably more than 100:1. With only 10 specialists, attrition can become a problem quickly. It's a different optimization.
I've met quite a few lisp programmers over the years, about half of them mediocre -- particularly those who only knew lisp. Reason being that they learned lisp for a job, and that was just the language the job was in. I might believe that only good programmers pick up lisp on their own, but mediocre programmers follow the money.
The excellent lisp programmers I've known have been polyglots -- folks who can dig deep, know how memory works, know how cpus work, know how their lisp works under the hood. The mediocre ones just bash stuff together, oblivious of the details, and the result is no better than javascript.
I’m intrigued that you’ve experienced a world where people learned Lisp just to get a job. Would you please elaborate? I confess that I can’t imagine an employer that desperate for Lispers today.
The driver is actually that the company needs people with a specific skillset, and their tooling is in lisp. As I saw elsewhere on HN today: "you can teach a biologist to program, but you can't teach a programmer biology". I don't think anybody is "desperate for lispers" unless their senior guru is recently departed.
I haven’t met anyone who started with Lisp, only those graybeard types who ended with Lisp after 20 years. Where do people work with Lisp at an entry level? I can imagine that code base would be a shitshow unless they have a ridiculously competent architect.
Lots of people had their first, and possibly only, programming exposure to Lisp as the scripting system for something else (i.e. Emacs, AutoCAD etc.) I'd go so far as to speculate that orders of magnitude more people learned it that way than have ever learned Lisp for the sake of learning Lisp.
Probably the same in APL, Coq, Prolog and Haskell etc. Weird but mathematically oriented languages that don’t easily get you jobs are persued by passionate programmers. It is like there are no mediocre hikers on the north pole!
Because such simple one-factor sentiments, even if they are true, are not how people evaluate using one thing over another. At best they might consider it in a multi-factor analysis. But with this particular sentiment it still probably won't be considered much because it's too hard to evaluate the truthiness of such a general claim -- I suspect it's more true in some cases but not so true in others. You'd be more interested in considering the specifics of language+ecosystem (not language alone) and how they relate to your problem domain.
Much like the sibling comment I have heard variations of this proposition before. But instead of wondering why don’t more groups take this approach, I want to know what make it possible in the first place. So, in your experience, or even just via some passes down stories, etc., what is it about Lisp that allows for this efficiency?
I have heard, although it is always just a quick statement with no explanation that it is the macros. And then one of siblings children comments seems to support the idea that Lisp programmers as a whole may be more experienced/better/more well rounded developers in general, so maybe that’s it. I am genuinely interested in peoples thoughts on this matter and am not being flippant or sarcastic.
I can't speak from a professional level about this, but I'll tell you why I started using Common Lisp for my personal development.
One day I was thinking it would be awesome if someone created a really powerful language with great facilities for abstraction: first class functions, objects, meta objects, etc. It should use dynamic typing during development with an excellent REPL and a built in debugger available everywhere, but it should have the ability to add type declarations when the code got more settled.
Even better, this language should include ways of hinting to the compiler how to make a chunk of code faster, and if that wasn't enough, you should be able to replace chunks of code seamlessly with highly optimized C code.
I thought about how to implement a language like this for a while, but when I looked into it I discovered Common Lisp does most of this already. It's static typing isn't perfect, though now there is https://coalton-lang.github.io/ if that's your thing.
So that did it for me, but really this is only part of what you can do with Common Lisp. I think it still has a niche in places where the "right thing" isn't know yet.
For example, I read a Reddit post saying that Common Lisp would be a poor choice now for a web startup, and that Paul Graham overstates Common Lisp's case as the reason for Viaweb's success. This is probably true in 2022, but I think it's instructive to look at why Paul claimed Lisp was so helpful back in 1996. There was no Rails or Django, no React or single page web apps. Viaweb built Scheme style continuations onto Common Lisp to simulate an SPA before AJAX was a thing, and on top of that created a slick HTML templating language based off lisp macros.
To do that in Perl, or C, would have required something like writing a scheme interpreter, and would have taken much longer for a 2 person team. Is that a 100x advantage? Hard to say.
Ultimately, I do think it still has advantages, you just have to find the areas where nothing else will really do the job.
Lisp projects also tend to keep the dependency list short.
In the best case scenario, once the foundation is laid and the project has momentum, you end up with what feels like a language finely tuned to express solutions to problems in your domain.
In other languages, you may reuse useful routines but it's not as powerful. Additionally, as the dependencies are added the interactions between them can become a real headache.
What's interesting to me is that for some problems Lisp feels like a cheat code and it goes exactly the way I just described. For other problems it feels like a weird old language with a lot of parens. Perhaps I'm just not good enough at Lisp though.
It's really not that much more efficient when you compare Lisps to modern languages that share features like interactive (REPL) development, garbage collection, large standard libraries, concurrency primitives and abstractions, object/functional programming styles, integrated package managers, etc.
When you compare modern languages, including Lisps, to something like C99, I think it's easier to see how you can be much more efficient/productive.
If you take away the similarities of Lisps and modern languages, you're mostly left with the syntax and how the syntax enables macros that set Lisps apart from other languages. But, most of your Lisp code looks very much like your other code where you're writing functions, defining structures, calling object methods, etc. so it seems a stretch that the syntax and macros alone make you much more efficient/productive.
> It's really not that much more efficient when you compare Lisps to modern languages that share features like interactive (REPL) development, garbage collection, large standard libraries, concurrency primitives and abstractions, object/functional programming styles, integrated package managers, etc.
pick 2!
But seriously, what modern languages have all these features?
Java/JVM languages, C#/CLR languages, Python and Ruby (minus real threads, but compare to Racket with not-the-best real threading story), NodeJS (minus the "large" standard library, but compare to Scheme with a small standard library), can probably include Go
I don't think any of these have REPL-driven development. They might have a "REPL" but not interactive code reloading as a part of the development cycle as is meant by a Lisp REPL.
Python with a Jupyter notebook is a very solid REPL development environment:
- Prototype code in Jupyter. Write first as a few lines of code per cell. Then merge into functions. Focus is on 5-10 cells becoming a single function.
- When working, copy the functions back into the main Python file.
- Periodically reimport the main Python file back into Jupyter and recalc the cells currently in scope.
- Repeat...
- The main Python file ends up mostly like an API. And the Jupyter notebook as docs on how to call that API.
i agree that python's repl environment is nice. i worked with python and jupyter for much longer than with common lisp. actually due to my domain it is still my main language. however i was taken aback when i first saw repl development in lisp. it is just far more seemless and stable. how often do you need to do python kernel restarts in jupyter? what i found extremely surprising is the huge performance difference between sbcl and cpython. common lisp as implemented in sbcl produces some of the most performant computations out there. also writing code in s-expressions turned out to be an unexpected killer feature for me. finally something you cannot do in python that is built into lisp is being able to debug and live edit a running (production) image.
while i continue to use python the same is no longer true for jupyter. i think using org-babel in emacs is a much more superior experience, with the added benefit of having the whole development environment available to you
How does 'REPL-driven developent' work, exactly? Are you writing code in files and then testing it in the REPL? Or writing substantive code in the REPL and then copying it to files somehow?
It's how I've worked day-to-day for thirty years or so, so here's my take on it:
I generally work in Emacs. I'll have one or more source files open, plus at least one REPL buffer. The REPL is my communication channel with the running Lisp.
The object of the game is to teach the Lisp interactively how to be the program I want. It's already a working program; it just isn't the one I want to build. I'll use Lisp expressions to teach it, one expression at a time, how to be what I want.
The contents of the source files depend on the stage I'm at with a program. If I'm just starting then it's probably one file with a few snippets that I C-x C-e to send to the REPL to modify the dynamic environment of the running Lisp.
If it's a more mature project, then I have a bunch of source files that fit into an ASDF system (which defines sources to build and dependencies among them and any libraries they depend on). The system as a whole will be loaded into the memory of the running Lisp, converting it into a work-in-progress version of my app.
I'll have some subset of the project files open in buffers so that I can add or edit definitions and C-x C-e them into the running Lisp and see in the REPL whether my changes have the effect that I intend.
I continue this way indefinitely, teaching the running Lisp expression-by-expression the features that I intend for the finished product to have. When the difference between my idea and what the Lisp does shrinks to epsilon, the program is implemented. I run a build function and I have a delivered application.
When something goes wrong during my work, I land in a breakloop, which is something like a backtrace, except live. Rather than a printout of an unwound stack, it's a live REPL on the dynamic environment of the stack at the moment the error occurred. I can use the breakloop to wander up and down the stack, inspect and edit variable, type, and function definitions, and resume execution at the moment of the error when I'm ready to see the effect of my changes. The Lisp then runs the same function from where it broke, except that the variables, types, and functions I modified now have the definitions I just gave them, rather than the ones they originally had.
If I change the definition of some class that already has live instances, then the Lisp reinitializes those instances with the new class definition and continues. If I neglected to show it how to reinitialize those classes, it drops me into another breakloop and offers me the opportunity to tell it how to do so, after which it will continue, as before.
If I stumble across something curious and I want to show it to a collaborator in context, I can save a heap image of the running Lisp and give it to my colleague. That colleague can start the image on their machine and see the same dynamic environment that I saw. In some older Lisps, that dynamic state could include all of the windows on my screen, and their contents, and which one was the active window, and where the text-insertion point was.
I can deploy my work-in-progress apps to a staging machine with a repl server built in. I can let it run in a testing environment indefinitely, and use Emacs to connect to a live REPL that I can use to rummage around in the running app, inspect and edit variables, types, and functions, and generally do anything I would do if it were running in my normal dev environment. If I see something odd, I can again dump a heap image, copy it back to my development machine, and crawl around in its running state while I let the deployed test version go back to doing what it was doing.
There's quite a bit more to it, but with luck, that gives a general idea of what the workflow is like. Common Lisp environments are generally like this; some have richer sets of affordances than others. Smalltalks are like that, too, and so is Factor.
Most other Languages and repls are not so much like that. Clojurescript with figwheel gives you part of it, and the part it implements is pretty good.
> I can deploy my work-in-progress apps to a staging machine with a repl server built in. I can let it run in a testing environment indefinitely, and use Emacs to connect to a live REPL that I can use to rummage around in the running app, inspect and edit variables, types, and functions, and generally do anything I would do if it were running in my normal dev environment.
Not the GP. Thanks for the comment, I always find your comments about your experiences with Lisp insightful... But I'm curious, does/can this lead to situations where colleagues are stepping on each others toes in the live environments?
If you're going to test that way, you want to have your own staging environment, distinct from other developers', just like you don't want two different people's unit tests writing to the same test data as they run their tests (unless that kind of race condition is exactly what you're testing, of course).
Very interesting, thanks! This is indeed how I tinker with my .emacs file, though I’ve only done relatively trivial stuff there.
What do you prefer about using C-x C-e on individual sexps rather than reloading everything and keeping the entire program synced between source files and the running environment?
Generally speaking, I work by building some data that represent my understanding of the model I'm working with, and some functions to operate on that model. My models start out simple and more or less wrong, and as I work, I build improved understanding. Mostly my understanding improves incrementally, and so does my code. I build up the app piece by piece, adding and changing things bit by bit. So most of the time, changing a small piece is all I need, and that's what evaluating one expression does.
Moreover, if I recompile everything, then I'm rebuilding my in-memory state from scratch. Mostly, that's not what I want. Mostly I work like a sculptor: I make a rough approximation and then refine it stepwise. I don't want to rebuild from scratch every time I discover something new. I want to keep most of what I've built and change just what needs to be changed.
That said, sometimes a discovery does call for a larger-scale reconstruction. That's when I reload a whole file or, in more extreme cases, reload an entire ASDF system of files. Once in a while, I change enough (or make enough mistakes) that it makes sense to blow the whole thing away--kill the Lisp, restart it, and load the system from scratch. But that's fairly rare.
Mostly I want to plop down my clay and tweak it a little at a time toward my goal, discovering and refining it a little at a time.
From what I've seen, the cycle is a bit like this:
- launch the program you want to run and have it running in the background
- text editor open
- bits of code in editor loaded in the running program through text selection and sending them to the be loaded (the most common scenario is doing this in Emacs)
However my concern with this is... if you don't run the entire "code frozen" program at once, how can you guarantee the internal consistency of the program if over time you kind of haphazardly add bits of code to it? Maybe you loaded that function, maybe you didn't, did you add that dependency function in the correct order and at the correct "version" (where version is used loosely, every time you type in something, it's a new "version").
I'd really love for someone experienced with Lisp to describe their workflow and also maybe clarify how they handle this (in my opinion, huge) problem of possible program inconsistent states.
For Clojure there are libraries to refresh the program: these stop the app, reload and evaluate all the source code files, and restart the app to ensure you are working with a consistent state that reflects the source code.
Between such reloads you might end up in inconsistent states,
but you benefit from fast iteration:
My workflow is to update functions in the source code, send to to the repl, quickly test them in the repl, and once done, I save, commit and push the code.
CI then runs the test suite from the source files.
I guess it just doesn't really come up that much? I personally aim to have whatever I'm not currently working on written to disk, and very rarely redefine things in the REPL once I've written them to source. Other than that every time you change anything it's automatically propagated, with a few known exceptions (macros mainly). I can say I've never wound up in an unknown state, and I'll keep a slime server running for days.
Well, not the same thing but Java can hot-reload classes (to a degree depending on implementation). But what truly makes repl-driven development in lisps so good is the more functional approach to development. Hot reload gets better the smaller the replaceable units get. Lisps have it good with basically paren-level hot reload.
GP didn't mention native code generation, which is a pretty compelling aspect of Common Lisp. I know there are some JITs for Ruby but it seems MRI is still canonical, just like cpython for Python.
I have heard the same kind of claims about Ruby, Python, JavaScript, non-typed languages, functional languages etc. as well. I still have seen zero evidence that any of those claims are true. I think those claims are often made when somebody feel super productive using language/technology X, and then jump to conclusions about X based on that feeling. Seriously, if Lisp was indeed 10x more productive than competing languages, I would have switched to it a long time ago. It would be silly not to!
How many languages do you know? You might find some inspiration in answering your own question by comparing what makes your efficiency different in one or the other. If you find your efficiencies are roughly the same, I might suggest you aren't using each language to its fullest potential and are writing in a lowest-common-denominator style, but that really might not be the case and perhaps the efficiency gains and tradeoffs have just been balanced well for you, so you'll need to decompose individual (in)efficiencies. For example, in one language you might not need to wait for a lengthy compilation cycle before you can run the code after changes, but with a beefy enough computer (or a networked supercomputer constantly doing compilation for all developers) perhaps the other language's lengthy compilation cycle is not in fact so lengthy for you. Or in another language, you might have strings with built-in pattern matching facilities that don't even need an import statement, if you need such things you'll be at an advantage over languages without them -- until you discover that for some other language someone else has already written a nice regex library with syntax that isn't too annoying even if it's not quite as elegant as something that's part of the language, and so the advantage narrows or disappears. (In regards to the GP's comment, you might very well get by fine with a Java team of 10 just like the Lispers, because 90+ other Java programmers have already written what you need in the broader Java ecosystem which the Lispers take for granted as part of the language, allowing you both to focus on the problem without distraction.)
I'm a fan of JRebel for improving efficiencies in Java development, in one of their marketing materials (https://www.jrebel.com/sites/rebel/files/pdfs/rw-mythbusters...) they claim that waiting on redeploys takes up about 20% of a Java developer's salaried time. So with naive assumptions if you had a team of 100 developers, you could fire 20 of them and maintain the same pace just by forcing the remaining 80 to use JRebel. Or just keep all 100 but now everyone's got a 20% efficiency boost and can do 20% more than before! (Yadda yadda real world caveats.)
For Common Lisp, this "no waiting for redeploys" is part of the language, you've been able to enjoy such a feature for decades without having to wait for JRebel to come into existence/figure out how to add it to a language yourself (some game studios accomplish approximations with their custom C++ engines), so it's a possible efficiency gain over languages that don't have a way to balance it -- like with JRebel which comes close, or to a lesser degree by more disciplined unit testing that lets you confidently and accurately make changes without needing to redeploy the whole thing for verification, or writing in a more purely functional style where you don't additionally suffer the burden of having to rebuild up tons of state after a redeploy, or to another degree by solving everything with an advanced type system, or just by having simple problems where you need integer-factor efficiency differences for them to matter for the duration you'll be dealing with the problem...
CL has a bunch of other stuff built-in that can lead to efficiency gains too; macros of course are a big part of that but not the only other part. I'll list a few examples of macros being useful. There's a macro that's been around in the ecosystem since the 90s that lets you write things in infix notation, so you can write your #I((-b + sqrt(b^^2 - 4*a*c))/(2*a)) and not have to live with (/ (+ (- b) (sqrt (- (expt b 2) (* 4 a c)))) (* 2 a)). (In any case negative sqrt will give you a complex number automatically, which is nice.) The built in "loop" macro for looping has some very advanced features on top of the more common for-i-.. style or for-each.. style of other langs, e.g. from Practical Common Lisp:
(defparameter *random* (loop repeat 100 collect (random 10000)))
(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))
(Symbols being first-class (that is, "maximizing" or "minimizing" aren't function names or strings) enables a lot of nice features apart from macros themselves.) It's not particularly hard to get such similar statistics from a list of numbers in another language, but having it be this easy and terse can give you a marginal efficiency boost if you happen to need to do something similar. The string formatting function "format" (not macro) has similar flexibility and any time I have to output a comma-delimited (except the last item) string of things in other-lang I get sad I don't have Lisp's format. Marginal efficiency boosts add up. The final macro example is that in Java we eventually got try-with-resources syntax (https://docs.oracle.com/javase/tutorial/essential/exceptions...), or in Python we eventually got the "with" statement, meanwhile in CL there's always been a style of "with-" macros that address the same issues. Some "with-" things are built-in, but it's trivial to write your own just like it's trivial in Java to implement AutoCloseable. Macros in Lisp can be about as easy to write as C preprocessor macros, though instead of string substitution into a template you're technically doing expression substitution, but Lisp macros can also manipulate the incoming data and run any other Lisp code before it produces some expansion, making them capable of far more when you need them to be. e.g. the boolean operator "or" is implemented as a macro that expands into a conditional evaluation (second+ operands won't evaluate if the first is true). Historically this has helped Lisp programmers "steal" any neat features from other languages without having to wait for an update to the Lisp implementation or standard. That has more to do with how Lisp has continued to be relevant though.
Hopefully at least I've given you an idea of how it's at least possible for there to be any efficiency gains using Lisp, either in the past before other languages and their ecosystems caught up, or even now for certain classes of problems (e.g. if you believe 20% efficiency gain is possible by eliminating waiting on redeploys while developing). Though I think marginal efficiencies that sum up to 10x are probably pretty rare nowadays. Such a general claim was more tenable in the past when even garbage collection wasn't really mainstream...
Such a strong claim requires a similarly strong evidence. And I don’t know of any empirical evidence stating that, so I will remain with Brooks’s claim that no 10x productivity boost is possible between high level languages.
Sorry but that simply isn’t true. And I know Lisp quite well, and have written my own Lisp implementations just for fun. I like Lisp in many ways but it is not my first pick when it comes to productivity.
When you capitalize lisp as in Lisp, that usually refers to Common Lisp (also the lisp being discussed in the whole thread). Have you implemented Common Lisp?
Nope! When you don't capitalize lisp, it refers to a speech impediment.
LISP in all caps refers to classic Lisp, and was once widely used for the family: all kinds of dialects and implementations used LISP in their names, even Common Lisp ones. "Common LISP" was a thing; e.g. in the title of the book Common LISPcraft by Robert Wilensky.
This situation was similar to how other languages were capitalized: FORTRAN, COBOL, BASIC. I suspect part of the reason for all the shouting was the limited support for lower case characters in some printing/terminal equipment. Many of the names involved were acronyms, or near acronyms.
Today, and for probably at least three decades, those languages have been called Fortran, Cobol, Basic (e.g. Microsoft Visual Basic, not Microsoft Visual BASIC). It's the same situation with Lisp.
Thanks for clearing that up. I have a memory of reading some conversation here that explained that Lisp usually refers to Common Lisp and people refer to Scheme specifically. It was long ago though. In any event the topic of the thread is definitely Common Lisp and I suspect that the parent was not aware
I've collected a few links I've given out before on this subject if you'd like to read more into it: https://www.thejach.com/view/2022/1/thoughts_on_writings_on_... To reiterate some of my thoughts (which are far less interesting or important than the links) I think it's a very old and tiresome and largely pointless debate, even if it can be a fun waste of time to ponder, but in any case it's mostly been lost. #lisp even gave up its CL-focused IRC channel in the move to Libera and is now at #commonlisp.
But that's just like most debates over words and changing common usage meanings. It doesn't even matter if the new common usage is or becomes the most popular usage or not, at some point it's common enough that a new entry in any dictionary is warranted. (The term "Lisp" obviously predates Common Lisp, but part of the success of Common Lisp led to "Lisp" gaining common usage to refer just to CL.) It's unfortunate that the alternate usage isn't something crisp, like how "literally" can be taken to mean something not literally true and is just an exaggeration or emphasis, and instead a common usage of "Lisp/lisp/a lisp/Lisp family/Lisp dialect" is as a poorly defined fuzzy feeling of the spirit or flavor of "Lisp-like" languages. It can be a mess trying to pin down whatever commonalities are meant by that feeling. My favorite attempt is something like a language written in its own literal data structures. But depending on the speaker the feeling might encompass things like WebAssembly (s-exps sorta!) or Dylan or even Julia, and in the past has once encompassed things like Ruby or Python (in the sense of "acceptable lisp").
For me and many others (like the title of this thread) unqualified Lisp still typically means Common Lisp, it's still a common enough usage, and I'll at least keep using it that way almost all the time for the foreseeable future just as others avoid using "literally" as "figuratively" or "virtually". But I don't think it's worthwhile to do so from a "fight the good fight" standpoint or to be consumed by a melancholic desire for a rectification of names. On the brighter side, at least for Lisp if there's communication confusion it's probably only a good thing in producing cognitive dissonance and driving some curiosity towards CL. (For example if someone talks about unqualified Lisp in conjunction with the form of GOTO that CL has which has been there since LISP 1.5, or in conjunction with OOP, or the function compile-file, someone reading with a particular fuzzy usage of Lisp in mind may think "I thought Lisp was a functional/minimal/interpreted language?" and go on to learn something. Similar positive learning benefits can come from using the fuzzy meaning of Lisp in e.g. setting up events or community spaces, where Schemers or Clojurists or whoever are welcome, since that gives more people in those other languages as well as the fuzzy-Lisp-curious a chance to learn about CL, and CL people a chance to learn about what's going on outside the bubble.)
I think it's a convention, but I could well be wrong. Maybe it refers to LISP. But maybe it's wrong too. Nonetheless, the lisp being discussed in this thread is Common Lisp
Quite the opposite I'd say... in my experience, Lispers tend to say "Lisp" when they are being inclusive of the whole family of languages & its philosophies. This convention began way back in pre-Common Lisp days, when there was literally no common standard: much as we say "Unix" to refer to the family of related-but-different OS's that once proliferated.
Generally I've seen capitalized LISP used only to refer to the original language, from McCarthy's lab (e.g., versions 1 and 1.5). By the time Interlisp landed in the late 60's, the all-caps convention has already begun to slip.
That's not to disagree with your own experiences: I just suspect they are "regional", so to speak, and not reflective of the larger Lisp community.
> I just suspect they are "regional", so to speak, and not reflective of the larger Lisp community
yeah i think there is definitely a component of that which led to my claim. i think it is better that 'lisp' should refer to a whole family of languages when context is not obvious. even when context is clear it is helpful to distinguish what lisp one is talking about in order to avoid ambiguity
i think that most of things discussed here pertain strictly to cl. also implementing some random minimal lisp does not make you an expert in common lisp at all. try to implement common lisp and tell me how it goes
I started a project in 2021 using CL. I'm solo, but I think if your team adhered to a style guide that (among other things) enforces use of Quicklisp or similar for managing dependencies, and puts strict^H^H^H^H^H^H draconian limits on when macros are acceptable, it would be no worse than many other languages.
Macros (and in other languages meta programming) should only be allowed when the writer
is going to produce top notch documentation ^H write a oreilly-publish-worthy book on how the hell their thing works. With beginner tutorials!
It's not that I doubt Common Lisp but that I doubt the stability of an engineering organization (not that using the same tech stack forever is _necessarily_ the best thing). It's just so common for groups to switch stacks every 5 years.
Some stuff requires herculean efforts or are just very painful to do without macros. Clojure's implementation of CSP, core.async is one example. Lisp macros empowers experienced users.
“ Our Lisp services are conceptually a classical AI application that operates on huge piles of knowledge created by linguists and researchers. It’s mostly a CPU-bound program, and it is one of the biggest consumers of computing resources in our network.”
So what I’d like to know, is would a modern “AI” approach (ML/DL) based on literature samples as input, as opposed to classical AI sitting atop an expert system/linguistic knowledge, fair any better if you were starting, say, Grammarly today?
That said, I enjoyed the article and it’s nice to have an example of Lisp being used in prod. My only experience of it is from using elisp.
> What are the differences between elisp and lisp?
common lisp is a general purpose programming language with a well specified language and standard library. Elisp is intricately tied to emacs.
Notable differences are , till recently(?), elisp has only dynamic scoping for variables. Common lisp has, by default, lexical scoping for variables (while also allowing dynamic scoping). Common lisp has much better support for closures than elisp.
Common lisp has very mature commercial and open source compilers that produce very efficient code.
Common Lisp is a compiled language that has a standard. Like many standardized languages, it has multiple free and commercial implementations. It has a pretty extensive object orientation system with multiple inheritance and multiple-dispatch methods.
This is done all the time in Elixir without fanfare, and you don’t even need to use a DSL. One just uses maps and lists that basically map one-to-one to JSON.
That was my point, that you can have “literal” JSON in the language without special syntax, which is preferred since it can be processed with all the built in language functionality.
Understood, but the fanfare is coming from the fact one can take a language without JSON, or SQL, or infix notation, or ..., and add it as a library. It means the language itself is flexible enough to support future paradigms and standards at the code level without a language redesign.
I agree it's nice when something as common today as JSON is built in to a language. But for something like Common Lisp, whose roots are now nearly 40 years old, the fact it can easily support JSON literals is nothing short of amazing.
Every couple months I get this huge urge to dive into Common Lisp and use it for work/study it/become a Lisper, but something comes up. I see this, have the same urge, and need to constrain myself from buying all the textbooks.
Please help yourself to a free copy of my Common Lisp book (https://leanpub.com/lovinglisp and set the price to free). There are better CL books that cover a broader spectrum of the language, but my book contains both tutorial info and some of my own CL projects. Some people have fun with it.
I did one of the basic tutorials out there and got to macros. In a terse few lines you get to a nice unit testing framework! It gave me a feel for why people live it. But yeah I just need 5 years on an elite team who would take me under their wing, but I can’t afford to pay them!
We use SBCL for production deployment and CCL on most of the developers’ machines. One of the nice things about Lisp is that you have an option of choosing from several mature implementations with different strengths and weaknesses: In our case, we optimized for processing speed on the server and for compilation speed in the dev environment
Wouldn't using the REPL during dev remedy the slow compilation issue?
I used CCL recently at work. I needed to create a binary, copy it to a different machine and execute. SBCL binaries depend on a version of glibc that is not available in every Linux. Clozure CL binaries do not have that dependency, they are portable out of the box. Also, I think Clozure CL is more memory efficient than SBCL. I was running it on a low-memory cheap hosting.
In addition to it being a historically popular implementation, from the MCL days, there was a period of time when SBCL was still pretty rough while CCL was mature and performant. They've swapped places IMO in the past decade or so partially due to the excellent work by the SBCL developers while CCL has been less active over the same timeframe.
I switched from SBCL to CCL for some web services due to issues with the former's GC. Seeing how some developers greatly preferred the native Hemlock environment over Emacs, I made the switch globally without many issues.
These days I use LispWorks, although I tend to separate GUI code from back-end code and make sure the latter is portable across implementations. Running tests on SBCL also catches some bugs at compile time which is nice.
CCL was a hugely popular implementation for a long time. One of its main strengths was extremely fast compile times, and very predictable performance/assembly. The runtime also had a lot of nice configuration options.
I think its usage has declined a bit since development of CCL has slowed down.
I’d like to get back into lisp, but I haven’t found an environment that is as good as the AllegroCL one I used use. Everything seems to fall apart when using the debugger, or doesn’t quite have eval-just this-selection.
What’s been your experience with the debugger and integrated repl?
> "SQL, Lisp, and Haskell are the only programming languages that I've seen where one spends more time thinking than typing." - Philip Greenspun
> "I have heard more than one LISP advocate state such subjective comments as, "LISP is the most powerful and elegant programming language in the world" and expect such comments to be taken as objective truth. I have never heard a Java, C++, C, Perl, or Python advocate make the same claim about their own language of choice." - A guy on Slashdot.
"One can even conjecture that Lisp owes its survival specifically to the fact that its programs are lists, which everyone, including me, has regarded as a disadvantage." - John McCarthy, "Early History of Lisp"
"Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people." - Matz, LL2
I could keep going but most of the quotes on that page are gold.
To answer your question, though, you may need to write some programs in Lisp yourself. I recommend Racket (less decisions and setup than CL-just use DrRacket.)
I use it in my day job. We use it to write sensing and machine-control systems to reason about the data from telemetry, neural nets, and machine-learning systems, to compute strategies for those components, to compile the strategies to native code, and to control and coordinate the component systems.
We also use Python, MatLab, shell and bat scripts, C#, and C++. I work in all of them, but I use Common Lisp for whatever I can.
Clojure has many pleasant properties, but it’s painfully immature to a seasoned Lisp developer. That said, if I really wanted to use the JVM for business reasons, Clojure would be high on the list. Even so my gut instinct is ABCL.
Edit: response to child:
The most obvious thing is a lack of TCO. But there are plenty of other things like the limitations of a JVM based object system compared to the MOP. And then there’s the Lisp Machine heritage that shows through in forms like EVAl-WHEN. There’s the condition/restart system too. That’s just a few things off the top of my head. But in no way am I denigrating Clojure. It’s a good Lisp that meets important needs and I’d happily use it anytime it’s right tool.
I like Clojure okay, but it lacks the deep support for highly-interactive programming that I prefer. I've written fairly extensively about that subject in other posts and elsewhere.
To be fair, that kind of support is hard to come by outside Common Lisp and Smalltalk.
I miss Common Lisp when working in Clojure, but not vice versa. Clojurescript with figwheel is a pretty nice, pretty interactive way to develop web apps, though.
Actually they do use Clojure, at least they have open positions for Clojure Software Engineers. Also, I know that Vsevolod, the author of the article, is not with Grammarly anymore.
Development in Clojure is afaik noticeably different (or at least was in my experience) if only because Java quickly surfaces for example in backtraces. You also might simply not need Java libraries, so you lose considerable portion of clojure benefits.
I think programs in Clojure will be measurably slower, which for some applications doesn't matter. Certainly there is a rich set of libraries and other resources available in Java.
Lisp has been around since before you were born. If the majority of programmers as are still not comfortable with the language after that long, despite having learnt it in college, it suggests the language is fundamentally flawed.
Imagine a blog post titled "Using C in production"; it sounds absurd.
The majority of programmers did not learn Lisp in college. Most universities don't have it in their curriculum, and if they do the closest is usually a "programming language" course that gives 1-2 weeks of coverage for 5-15 languages.
That was different when I learned Lisp. Our CS intro courses were either Scheme + something else or even Common Lisp + Ada. Basically every CS student at the local university had exposure to either Scheme or Lisp then. There were a bunch of research projects that were mostly using Lisp: advanced chat systems, image processing, planning, diagnosis, route planning, music theory, ...
I'm not sure if that's supposed to be a counterargument or not. I mean, MIT taught SICP for over 20 years with Scheme before dropping it. So it may be true that a majority of MIT trained programmers learned a Lisp in college. But that's not the typical experience across universities, and I doubt it ever was the case that the majority of universities taught the majority of their CS students with a mandatory Lisp course (that is, a course beyond the survey-style course I mentioned before, which seems to be far more common course).
Even top universities didn't require it. Georgia Tech, one of the top technical universities in the US, did something like a 2-year stint with a mandatory SICP course before dropping it in favor of Python (IIRC), and had no mandatory Lisp course besides that (though they did have a mandatory Smalltalk course at the time).
And? I was responding to the OP's absurdist claim that the majority of programmers learned Lisp in college. They then tried to use that same absurdist claim to draw a conclusion which is, in a word, moronic.
A key to running Lisp in production is to step away from thinking of it as a lone-wolf bionic-suit hacker language, and to invest in developing a style guide, code review guidelines, CI/CD, and a culture of training new programmers to write Lisp. I've found that you typically don't have to hire Lisp specialists. As long as you find good programmers, they pick up Lisp just fine in just a few short weeks.
The sibling comments are right though: Lisp's reputation is unfortunately affected by so, so many myths that it actually stunts the ecosystem in certain ways. The most rampant myth these days is that (somehow) macros automatically imply doom of a codebase after a certain size or contributor count. Classic myths from decades ago, like "Lisp is interpreted and slow", still echo from time to time too. Lisp's extensive, half-century history is a strength but also clearly a (social) weakness.
A lot of myths come from good-intentioned speculation of the supposed consequences of certain features or aspects of Lisp, and not from actual experience using it.