How I lost my faith in Lisp (2002)
groups.google.com
groups.google.com
With what I've learned in the last five years I've (1) written a Common Lisp compiler that interoperates with C++ and uses LLVM as the backend (github.com/cando-developers/clasp); (2) I've used it as the basis of a programming environment for designing new molecules and materials; (3) we've developed a Jupyterlab kernel and ported Jupyter widgets to Common Lisp as the graphical user interface for the programming environment.
I say "I've" and then "we've" because while I started this myself - several people have joined me and we are now turning it into products.
Common Lisp is great - no other language is as rich and expressive and fun to program in. Real macros (code that writes code!), multiple dispatch, conditions and restarts - it goes on and on. There are lots of features in Common Lisp that haven't made it into other languages.
[edit]
Oh - and then there is this: http://greenlab.di.uminho.pt/wp-content/uploads/2017/09/pape... Of all the dynamic languages (and who doesn't like dynamic languages?) Common Lisp is the most energy efficient by a long shot.
I know that common lisp (the spec) explicitly doesn't mention any of this - it was the early 90's so who cared anyway - but how would you fit common lisp into a modern server-side app that has to process many things at once? Or is that just not an area that it's concerned with?
1. The summary here seems to be "modern high-level languages, used, well, are just as productive as Lisp." Does that seem right?
2. One of the tensions for me in technology is between love of simplicity and love of complexity. An example of the latter is Enterprise Java, where the tendency toward a FactoryProxyBeanMutatorFactoryInterfaceImplementation is well known. Is the perceived superiority of Lisp perhaps because it attracts people with strong simplicity bias?
3. Every "Lisp is super-productive" story I hear is about a lone individual. Is Lisp's suite spot that of the solo programmer? Since the rise of the Internet, I think most software has shifted to be about teams, and I'm wondering if Lisp is less suited to team collective ownership or projects where many teams are involved.
I can't speak for anyone else, but some of the most productive research coding I have done was in lisp.
I do think it is difficult to work in large teams with lisps, their flexibility becomes a barrier to communication. The enterprise model of "100s of programmmers, all fungible" isn't quite right anywhere, but it really spectacularly falls apart in an environment like lisp.
I do think lisps are amongst, if not the, most productive languages for one programmer (or a very small team that works well together) to do novel, exploratory programming. This fits really well in some types of research.
On the other hand, if a lot of what you want to do is basically glue - lisp doesn't buy you too much.
For example, I don't thing python is a very productive language, but it is a very productive ecosystem - if that makes sense. Far more so that lisp(s) today for many problem domains.
If you really want to start something basically from scratch, it's still a very good match. But if you are going to spend a lot of time building 70-80% solutions for problems that in another environment would be one include away ... maybe you won't be so fast.
1. Yes, more or less. LISP used to be superior to everything else but modern languages have caught up in most areas. LISP still has a few special tricks like MOP in CL, macros, dynamic loading of code, resumable exceptions, but these are rarely needed in everyday programming.
2. No, not at all. Neither CL nor Racket nor any other mature LISP and Scheme dialects are simple to use and easy to learn. They have long-steep learning curves, especially idiomatic CL. The syntax is somewhat simple if you ignore special reader extensions, but that's irrelevant. CL is a large language, you need to learn both imperative and functional programming techniques, and then there are tons of libraries and conventions to learn.
3. Yes, I would say. LISP is incredibly powerful in the hand of one hacker who really knows the system. You will get awesome results very fast and can do things that would be really hard in other languages. It also encourages high level abstractions like no other language I've ever seen. But the main disadvantage of LISP is maintainability. It may be hard to even understand your own code a year or two later, let alone that by other people. Everybody has his own stile and every larger program will create a DSL you have to learn in order to understand what it does.
LISP allows programmers to use abstraction so powerful that sky is the limit. Problem is, humans have their limits, too. And different humans have different limits. Abstractions are powerful, but then you have to think abstractly in order to use them properly.
When you are good at abstract thinking, LISP will liberate you. When your colleague is better than you, or just as good as you but has more LISP experience, reading their code will make your head hurt. To make you two cooperate, your colleague would have to give up some of their powers... but the ability to use those powers to their maximum was the thing that made them love LISP. So now one of you is going to suffer.
Other languages often put artificial limits to your abstract thinking. For example, you have a few parts of code you realize are somehow just different instances of the same pattern; the pattern could be extracted and reused... but doing it in this language would either be impossible, or the outcome would be really ugly, or it would require writing so much boilerplate code that the more abstract version would end up being longer, less legible, and not really nice at all. So you sigh and don't do it. And the same thing happens to your colleagues in similar situations, so now you are all writing approximately on the same level of abstraction.
In other words, with lesser languages, the frustrating thing is the language. With LISP, the frustrating thing is other humans (and that may include yourself on a different day). But the frustration is always there. Unless you are really good and working alone, I guess. But that puts the company that employs you in a dangerous situation, so it is unlikely to happen.
(Then of course there are also other problems, such as companies wanting to keep all their employees completely replaceable, which is incompatible with people using their unique skills.)
For me, one of the key determinants in how I write most code is how approachable it will be to the next person. Because anything significant is going to involve more people, and I don't want to have to be chained to my past successes.
I think there's an analogy with writing. If I'm writing something for myself, or for a narrow, specialist audience, I can indulge my desire for all sorts of things: abstruse ideas, obscure words, Dickensian sentences, punny wordplay, tangents galore. But when I'm writing here I try very hard to rein those desires in. Because here the writing isn't about me.
So I think LISP's ability to turn my ideolect into a tower and creeup up into it is exactly what I don't want in a tool.
The tooling alone is sufficient reason for me to use lisp. Even commercial IDEs for python (e.g. pycharms) are nowhere near as good as slime, plus sbcl is a compiled language. I can change a function, run a test and get instruction level profiling information. Pretty much no modern dynamic language lets you do that, and the non-modern static languages (e.g. C++) take longer to link (much less compile) then it takes me to do all of those steps for incremental changes in lisp code.
2. I have a strong simplicity bias, so I can't argue there. I will say that lisp is good at "getting out of your way" which helps remove a lot of accidental complexity. Java (particularly the Java from 15 years ago), is notoriously bad at "getting out of your way" so they are near opposite ends of the spectrum there.
3. Lisp works fine in teams; most languages with small communities have fewer team projects just because the set of possible teams grows quadratically with the size of the community. This is exacerbated in the lisp community which historically has several silos. For open source projects, SBCL (which is written in lisp) is the first team project that comes to mind.
For commercial software, QPX comes to mind; ITA was listed as having 400ish employees, I'm not sure how many were working on lisp code though.
Everything about FP is conceptually good except for the human element. I find other people's FP examples to be exceptionally hard to read. But in fairness not as hard as object-oriented programming (OOP) IP languages like Ruby or Angular. I picture them as two extremes: abstract formalism with FP on the one hand and syntactic sugar/convention/patterns with IP/OOP on the other. I'm classically trained so to speak, so I can make the mental leap to FP when I need to. But I continuously have trouble with IP languages because for the most part I don't understand what problem they're trying to solve.
I think Elixir, Clojure and F# are making inroads on the FP<->IP/OOP front but they still aren't easy enough for mainstream adoption IMHO. Haskell, Scala etc are too fringe and have probably already reached saturation.
Also I do agree about the ignorance aspect. Most programmers I've met don't understand the difference between simple and easy, as examined in depth by Rich Hickey:
http://web.archive.org/web/20021113063322/http://www.gembook...
Link to pure article headers+body:
https://groups.google.com/forum/message/raw?msg=comp.lang.li...
Ouch.
And in further posts, Erik responds,
"Sigh. Will you _ever_ get a clue? (For full credit, your answer must be 2000 words or longer.)
"A free hint for you: Cut your losses and just _move_on_. If Python is so great, enjoy it for what it is, and make it your new community. Pursue your happiness -- if it is to be found elsewhere, move accordingly. Hanging around here apparently makes you progressively more unhappy."
e.g. Naggum on XML: http://harmful.cat-v.org/software/xml/s-exp_vs_XML
He uses the hash table as an example, and I think it's apt. Lisp does feel "old" to me with respect to having 10 different choices for hash tables in 10 different dialects. (I briefly worked with Julia's femtolisp a couple years ago and felt this.)
I also felt it when trying OCaml like 5 years ago. I loved the language, but having to "choose" which hash table to use felt odd.
Newer languages like Go and Rust (I think) both have Python/Perl-like hash tables built-in, or at least close to the core where all libraries can interchangeably use them. I think this is here to stay. Hash tables won :)
These are some of the most annoying part of any language: In Perl the key of a hash must be a string, in Haskell, String is a linked list. And so on.
In 2002, C++ had a plethora of non-standard hash-tables: http://www.drdobbs.com/the-standard-librarianhash-tables-for... Today there are a plethora of standard hash tables.
Yet C++ isn't dying like Lisp.
well yeah of course english is easier, else there wouldn't be these kind of tables : https://www.effectivelanguagelearning.com/language-guide/lan...
There's no equality amongst languages. Japanese students have to get up and do one hour of kanji learning every year from 8 years old to 18 years old in addition to normal language classes for instance - there's nothing comparable in english.
It’s based on the premise ‘as an English speaker’ these languages are easy to learn. But, if your native language where say Dutch you get a different list than if your native language is Japanese.
"The Foreign Service Institute (FSI) has created a list to show the approximate time you need to learn a specific language as an English speaker."
And what counts as "normal language classes"? Until at least high school in the US, every class other than math focuses on reading and writing.
Main quote addressing your question:
"One thing that many people found unsatisfying about my how-I-lost-my-faith posting is that I never really got around to explaining why I lost my faith other than saying that I saw people being productive in other languages. Sorry to disappoint, but that was basically it. What I think needs clarification is exactly what faith I lost. I did not lose faith in Lisp in the sense that it stopped being my favorite programming language. It didn't (notwithstanding that I switched to Python for certain things -- more on that in a moment). What I lost faith in was that Lisp was the best programming language for everyone (and everything), and that the only reason that people didn't use Lisp is that they were basically ignorant. My faith was that once people discovered Lisp then they would flock to it. Some people (hi Kenny!) still believe that. I don't."
I still think it's beauty is unrivalled but in the OO world, Typescript comes pretty close.
There are still plenty of successful but very small Enterprise Common Lisp companies, many of them being bought later and converted into something worse: Viaweb, Ithaka, Nintendo, NaughtyDog, ... KTI, Bentley or Grammarly still doing strong.
Wonder what critical features of Python are particularly hard to replace with Lisp extensions. Interface with other runtime environments?..
I am also very fond of Perl and I've been able to use it many times because it was already there (I didn't need to install anything) and I could find excellent modules on CPAN.
I bet Lisp would be way more popular if every Linux installation came fitted with it.
Did that. The Merriam-Webster, in fact. Here's what they said:
> There are several meanings of ignorant, all of which are concerned with a lack of knowledge in some sense; some of these are more insulting than others, and care should be exercised before applying this word to people who you do not wish to offend. Saying “They were ignorant of most of the laws of physics” means that the people in question did not have a specific body of learning. Saying “You are an ignorant person” is possibly describing someone as primitive, crude, or uncivilized.
https://www.merriam-webster.com/dictionary/ignorant
I'm going to resist the temptation to call the original author ignorant since I don't want to spawn some sort of infinitely recursive ignorance-accusation chain. Instead, I'll call him unintentionally rude.
This is not in the definition. Please try to stay honest when chastising someone for not being accurate.
> a : destitute of knowledge or education
> also : lacking knowledge or comprehension of the thing specified
> b : resulting from or showing lack of knowledge or intelligence
Where?
I try to be sensitive to issues of usage like this because civility does not come easily to me, and I have to be careful of what I say lest I inadvertently offend. And I am confident that when I have heard the word used, it is almost invariably in the larger sense. Use in the narrow sense tends to be by foreigners, who seem to be looking for a translation into English, and could easily not know the broader implied meaning.
If LN turns into anything, it'll be because of Lisp, not in spite of it. It really doesn't matter that the world is phobic to it when you alone are the blacksmith.
One could argue "See? It's running in JS. Doesn't that mean Lisp is useless?"
Maybe. But macros are a thing. And when you can generate React on the fly, without having to make a class for every single thing you want to do, the power disparity starts becoming very apparent.
There are interesting Lisp codebases, but you have to dig for them. Abuse (a game engine) comes to mind. http://abuse.zoy.org/browser/abuse/trunk/data/lisp
And what other language could let you add type inference with relatively little effort? https://web.archive.org/web/20070610012057/http://www.cs.ind...
https://web.archive.org/web/20070615124421fw_/http://www.cs....
(<a> href: "https://news.ycombinator.com" "Hacker News")
That lets you merge s-expression syntax with React syntax quite nicely. (<html>
(<body>
(<div> width: "100%" "Hello, world")))
Here's the output of a REPL session. $ rlwrap bin/lumen-node
> (load "arc.l")
> (print:compile:expand '(<a> href: "https://news.ycombinator.com" "Hacker News"))
React.createElement("a", {href: "https://news.ycombinator.com"}, "Hacker News")
> (print:html (<a> href: "https://news.ycombinator.com" "Hacker News"))
<a href="https://news.ycombinator.com">Hacker News</a>
> (print:html (<html> (<body> (<div> width: "100%" "Hello, world"))))
<html><body><div width="100%">Hello, world</div></body></html>
> (print:html (whitepage "Look ma, no Racket"))
Warning: Each child in an array or iterator should have a unique "key" prop.
Check the top-level render call using <html>. See https://fb.me/react-warning-keys for more information.
in body
<html><body bgcolor="white" alink="blue">Look ma, no Racket</body></html>
You can see it's actually JS, since you get all the same warnings that you'd normally get in a node repl. (It's literally running on Node.)And (print:html (msgpage 'shawn toofast*)) spits out a page saying "You're submitting too fast. Please slow down. Thanks."
I find it much easier to generate HTML than traditional methods, and much more maintainable. But it's not fair to claim that something new is inherently better. Time will tell.
I'm most interested in any unexpected warts, but there don't seem to be any so far.
(You can diff with the official sources at https://github.com/arclanguage/anarki/blob/f01d3f9c661eed055...)
Apologies for the nested replies; wasn't able to edit.