Readit News logoReadit News
samatman · 2 years ago
It's the lists.

No, not the prefix notation, parenthesis, what have you, although that doesn't help. The lists themselves. In Lisp, code is data, and data is lists.

Yes, of course, there are hashmaps, arrays, strings. But idiomatic Lisp code really does use linked lists extensively, it's an entire style of programming. Even if you'd prefer to use different data structures (and again, Common Lisp does support this), you still have to be able to read and reason about the many parts of the language designed for, as the old quip had it, prothething lithts.

The "weird looking syntax" does not help, but Lisp hackers are right that you get used to that part, might even appreciate it if macros are something you really care about. Structural editing a la paredit and parinfer are pretty nice too.

But when it comes with a weird way of programming, that's a bridge too far for a lot of people. It's harder to learn, read, and reason about, for longer than most languages.

I'm glad they mentioned Julia though. Learned everything Dylan had to teach and then some, real treat of a language, and, it turns out, writing macros without cons cells is rather pleasant and powerful. Certainly an acceptable Lisp in my book. Maybe someday they'll add conditions and restarts, that's the one feature CL which gives it an edge on Julia.

jjav · 2 years ago
I didn't see mentioned in the thread (maybe missed it) the #1 reason, IMO, that Lisp can't be popular in companies.

Everyone should take the time to learn Lisp and do a handful of personal projects with it. It'll help your growth as a software engineer. Just do it!

But that doesn't make it a great corporate language. Lips is infinitely flexible, you can mutate it to be what you want. That's cool and feels awesome.

Also: a maintenance nightmare as soon as you have more than ~1 person working on the codebase!

Everyone surely has heard the joke/truism how C++ can be great as long as you only use a sane subset. But every team uses a different subset. Now imagine something like Lisp where every developer & team morphs it in a different way and you have a product with hundreds of developers on it. Try maintaining that without going insane.

The anti-Lisp is something like Go. Simple, not very flexible, everyone does it the same way mostly, you can plug & play developers like scrum demands we do.

bitwize · 2 years ago
> Also: a maintenance nightmare as soon as you have more than ~1 person working on the codebase!

Lisp isn't any harder to maintain than any other language. The Lisp codebases I've worked on, even professionally, were originally written by talented, experienced engineers and were in fact wonderful to maintain.

> Now imagine something like Lisp where every developer & team morphs it in a different way and you have a product with hundreds of developers on it.

Dr. Ian Malcom's could/should distinction applies here. Most Lisp teams do not "morph the language" willy-nilly. They set standards of what to do and what not to do, establish a house style, build up a library of in-house functions and macros, and the more junior programmers imitate the more senior ones, just like any other dev team in any other language. And the vast majority of Lisp teams are small, even if they are working on large applications.

"We wanted to make it possible for very large projects to be done by small teams of people and for smaller ones to be done by one person." --Tom Diaz, Director of Software Products, Symbolics, 1986: https://www.youtube.com/watch?v=-K01FQ73xgY&t=144s

> The anti-Lisp is something like Go. Simple, not very flexible, everyone does it the same way mostly, you can plug & play developers like scrum demands we do.

I think you might be on to something. Symbolics was very much in danger of making large software projects possible by one person or a small team of people. It seems as if the corporate world has responded to the proliferation of more powerful software development tools -- not only in Lisp, but certainly Lisp and Smalltalk had an outsized influence -- by lowering the skill ceiling to make devs more fungible, and creating more and more process to hobble their productivity so as to justify larger teams of devs and dev-adjacent personnel: PMs, POs, scrum masters, etc.

brlewis · 2 years ago
In companies, most languages have some kind of system to enforce style guidelines and restrict which dependencies can be used. Companies already restrict the flexibility of the languages they are already using. So flexibility is not the reason Lisp is unpopular among companies.
shrimp_emoji · 2 years ago
> Simple, not very flexible, everyone does it the same way mostly, you can plug & play developers like scrum demands we do.

I think that's why Python beat Ruby. :p

fl0ki · 2 years ago
> The anti-Lisp is something like Go. Simple, not very flexible, everyone does it the same way mostly, you can plug & play developers like scrum demands we do.

This has not been my experience with Go. The only areas where Go actually enforces consistency is that gofmt has no configuration surface, and Go Modules conclusively won the dependency management war. Other than that, it's still a lawless wasteland.

Foreword: Go is not bad, far from it. It does a lot of things right and you can do a lot worse. But myths around its simplicity, idioms, best practices, etc. have created a generation of monstrous tech debt hiding behind tidy syntax.

One of the worst myths is that it's easy to see the right way to do something in Go, because now when everyone does things their own batshit ways, they each think they did it the obviously right way.

* Go has no build system, and you'll need one for anything but the most trivial projects. Many use `make`, but some people insist that `just`, `ninja`, etc. are worth people having to install extra dependencies. The worst is when projects use straight shell scripts, having all of the platform compatibility problems of make with none of the benefits.

* Go has no macros. Do you use reflection, code generation, or write everything out by hand. You can't even parse some JSON without being forced to make a choice here. (The standard library option, `encoding/json`, is the worst by far. It's also the most popular because of course it is.)

* Even when you're done with that, you still have to choose a way to validate that input, because e.g. Go doesn't even have a concept of a value being "required" so you'll be introducing that somehow. The "validation" frameworks (sigh) that have an opinion on this still do it inconsistently for different builtin types, and often silently do nothing for custom types. Good luck being consistent even within a project let alone between projects and teams.

* Go generics are very limited, and how you work around those limitations can vary greatly, e.g. do you use receiverless methods to simulate associated constants/functions or do you go back to reflection for those. There's still no solution for associated types, you either make do without them or abandon the type system altogether and use reflection. (In a LISP thread it might be hard to imagine just how bad this can get, because there's dynamically typed in a language that's built for it, and there's dynamically typed in a language pretending to be statically typed)

* Channels, mutexes, and atomics all have their place, but most people never understand their tradeoffs properly (and community myths do more harm than good), so not only do they architecture projects around different options, but often the wrong options for their requirements. People will make performance arguments with no measurements, and correctness arguments with no proofs, etc. and when you join an existing project you'll be sifting through its uniquely crafted wreckage to figure out what invariants can even begin to hold.

* The Go community has a lot of vitriol against testing frameworks, but Go has no useful functions for comparing values of non-trivial types, so you either use a test framework after all or reinvent one badly. You can't even define equality in Go recursively through pointer, slice, or map types -- strings compare by contents, pointers compare by address which is almost never useful, and maps and slices cannot be compared at all. It's not even consistent among builtin types. It's very common to use reflection here, see above, this is its own special hell.

* Go has no sum types, pattern matching, or enums. (No, multiple value returns are not enums, they are not a type you can use as a map key, they cannot nest, etc). You'll be reinventing these somehow with structs and interfaces and switches which have to choose to panic or ignore unexpected branches. Many projects, knowingly or not, create unenforceable sum types where different records use different subsets of fields of a struct. It makes C look modern and high-level, because at least C has unions.

I could go on. Go gets far more credit here than it deserves. Again, it does a lot right and it can be used well, but you should not expect quality or consistency from a broad range of programmers just because it's Go. Management that banks heavily on this myth generally pays for it dearly.

Karellen · 2 years ago
> But idiomatic Lisp code really does use linked lists extensively,

Idiomatic python code uses lists extensively. In my (somewhat limited) experience, they're the default data structure to use for a lot of algorithms.

Slightly more accurately, a lot of stuff in python uses sequences extensively, which are implemented by a number of types - but the default sequence is a list. And strings are lists. Yeah, if a list doesn't cut it then try sets or tuples or generators or coroutines or something else that implements a sequence. But for your initial prototype? List.

And python's pretty popular.

edflsafoiewq · 2 years ago
A Python list is an ArrayList/vector, not a linked list. CL lists are linked lists of cons cells.
jshaqaw · 2 years ago
People confuse code at the exploratory phase with final production code.

Linked lists are a massively flexible data structure which can be great when you are still feeling your way around a problem domain.

Once you have a good sense for the shape of your data it is relatively trivial to go back and update the codebase with performance optimized structures.

LeoPanthera · 2 years ago
I love Python's list comprehensions. When I first discovered them I had a kind of "mind blown" moment. They look like this, for anyone who doesn't know:

  squared_div_by_3 = [i**2 for i in range(10) if i % 3 == 0]
Without using a list comprehension, this is equivalent to:

  squared_div_by_3 = []
  for i in range(10):
      if i % 3 == 0:
          squared_div_by_3.append(i**2)

m463 · 2 years ago
I like python significantly more than lisp.

There are so many ways to express yourself in python that are troublesome in lisp.

I actually think list manipulation is easier in python than lisp.

I don't know, is there a lisp dialect that makes common data structures available in a multitude of ways?

I seem to be able to manipulate lists quite easily in python, and switch back and forth to sets or hashes.

but in lisp you have to dig in to find (for example):

- how to prepend to a list

- how to append to a list

- how to remove an element from a lisp

- how to do slices of lists

it seems to me like a lot of operations in lisp are needlessly efficient too.

Like instead of copying a list, you have to modify the list in place.

if my list will only have 10 elements, and my machine does millions of instructions per second, can't I copy it around a few times if I want?

richie_adler · 2 years ago
> And strings are lists

Eh, not really. Lists are mutable, strings are not.

Strings are iterable and sliceable, which makes them usable in many similar ways to lists, but they're not lists.

funcDropShadow · 2 years ago
> It's the lists.

That is one of the defining differences between Clojure and older Lisps. Clojure has list, vectors, maps, and sets as equally well supported data structures in the syntax and standard library. Classical Lisps often miss proper abstractions over different data structures. Clojure has those as well.

CyberDildonics · 2 years ago
I think it's strange that anyone would even ask why common lisp isn't popular. There is no payoff to writing something in it. The binaries are huge, it is going to be a lot less clear than modern C++, it won't be as fast, you still have a garbage collector, the libraries are niche, the syntax is reversed, the tools are niche, the ecosystem is niche, and everything you do is the opposite of what is intuitive at first.

Then on top of all this is built on linked lists which are essentially an obsolete data structure in their simplest form.

There is no reason to learn something with backwards syntax and ancient tools when there isn't even any payoff. Write something in C and the program is fast, small, native and can be compiled anywhere in a fraction of a second. There is still a payoff for all the very real pain. In lisp there is just no reason to use it from any angle other than how clever someone can be with macros and that is the exact opposite of good sustainable programming.

packetlost · 2 years ago
I don't think it's the lists. I think it's the cons cells. Lists are pretty ergonomic in most languages. As someone who loves Lisp (Scheme, specifically), cons cells are elegant for the compiler nerds and a complete nightmare for the programmer. Fuck `car`, `cdr`, `cdar`, `cddar`, `caar`, etc.. It's a horrible interface and every time I need to remember which variant gets me the value stored at the tail of a list I get a little more angry and want to write more Clojure and less Scheme.
IshKebab · 2 years ago
I disagree. I have no problem with lists obsession in other languages like OCaml.

The parentheses are just too much. I get how elegant and unambiguous they are for computers but I am not a computer. It's like RPN. It's elegant and easy for code to parse and unambiguous and all these nice things.... except it isn't easy for me to parse.

Compilers are perfectly capable of compiling readable code like Rust so I don't see why I should have to do the tedious work of figuring out all the parentheses manually.

Lisp is like a really great IR. But I don't want to program in an IR.

Zak · 2 years ago
> I don't see why I should have to do the tedious work of figuring out all the parentheses manually.

I think most people who write a lot of Lisp don't do that. I use Paredit mode in Emacs, which doesn't allow the parens to become mismatched and has operations like "move the last token out of this expression" and "jump to the next expression" so it actually feels like you're editing a tree rather than a chunk of text.

A quick search says there's an equivalent for VSCode, and I'm sure other editors have options as well. I've seen some amount of structural editing for languages that don't use s-expressions, but it's always pretty limited.

If you've written Lisp with a good structural editor and still don't like editing a program as a tree, then we think about code very differently.

lilactown · 2 years ago
I think it's as much about familiarity than anything else. I've programmed full time in Clojure for the last 6 years, and I find it just as easy to read than other languages I'm familiar with (JavaScript, Java) and way less easy to read than other languages like Haskell or OCaml that have their own syntax lineage. I'm sure if I spent an amount of time becoming familiar with them, I'd find them just as easy as I do Lisp.

There are certain things that languages can do that make syntax easier; for instance, Clojure's default constructs reduce a lot of parens compared to CL by using brackets [] and removing nesting. For instance

    ;; clojure
    (defn sum-and-square [a b]
      (let [sum (+ a b)]
        (* sum sum)))

    ;; common lisp
    (defun sum-and-squaer (a b)
      (let ((sum (+ a b))
        (* sum sum)))
This leads some people to assert (with other reasons too) that Clojure is not in fact a "lisp."

JohnFen · 2 years ago
> It's like RPN

That's genuinely fascinating for me, because I find postfix notation to be more intuitive and easy to parse than infix notation.

brlewis · 2 years ago
With Rust do you close all your } manually? Do you have an example of Rust code where the equivalent Lisp code would be harder to parse, assuming equal familiarity with both languages?
breather · 2 years ago
I'm tackling a significant lisp project right now, and the thing that holds me up right now is that the code is difficult to organize. Python, java, rust, go etc have well-defined patterns to figure out where code lives and where you might expect certain behaviors to occur. With lisp you can really shoot yourself in the foot very easily by using abstractions that are difficult to follow and are spread out across many files.
mark_l_watson · 2 years ago
I like to compose programs from small one purpose Common Lisp libraries, each is a Quicklisp project. I used to write larger monolith CL projects, but I like my newer approach better. Off topic, but I take the same approach for my personal Python and Racket projects also.
vindarel · 2 years ago
> the code is difficult to organize

we can simply do `(defpackage :mypackage (:use :cl))` then `(in-package :mypackage)`. Since they don't have to follow file hierarchy, we are free.

That's good for the long term, and general flexibility. But it's different, sure. Good luck!

freilanzer · 2 years ago
If there's one language in existence where you can shoot yourself in the foot using abstractions it's Java. It produces spider webs of dependencies, hierarchies, etc.
kagevf · 2 years ago
Lately, I've been creating protocols that are meant to be the interface for some kind of entity, such as "user", "utility", "configuration", "auth", and so on. The logistics of that are to use defgeneric for the protocol interface, defmethod in the same package, but can be over-ridden with a more specific defmethod in another package if necessary. I still export regular functions too, but I look to the defgenerics as the main entry points for a particular package. To (sort of) enforce some separation, I try to keep these packages self-contained in their own system (defsystem).

I mean, it's one approach, but my advice would be to take some time to come up with what would work for your appication and CL is flexible enough it can probably support it.

taeric · 2 years ago
I'm trying to understand why lists matter. Yes, there are some oddities where some base constructs don't play as well with hashmaps as they do with lists, but it is far from difficult to work with a hashmap. Or an array. What difficulty are you talking about, specifically? (Genuine question.)

Biggest difference I know of, off the top of my head, is the LOOP macro having constructs that care which one you have. Curious if there is more.

QuadmasterXLII · 2 years ago
O(1) access to the nth item turns out to be more important than O(1) insertion.
naveen99 · 2 years ago
More specifically, the linked lists are too inefficient for modern computing to be the default data structure. Not enough locality, too much jumping around memory. Reality is a tree, but to organize it, you have to convert it into arrays, maps, and matrix multiplication.
elviejo · 2 years ago
Reality is a graph. We understand it as a multi-tree. But we write it in lists.
valty · 2 years ago
It's funny that behind the scenes in all languages, everything is lists (in the AST).

It's strange that we tend to initially code in easily readable built-in control structures (if, switch, for, while), but then there always comes a point when you need to refactor...and convert them into lists of data structures and process those.

For example, if you are matching routes in a web server, you can write a bunch of if-statements. Very simple. Easily understandable. And you can use whatever criteria you want, in whatever order you want.

    if (request.pathname == '/foo') { return foo }
    if (request.pathname == '/bar') { return bar }
But say now you want to print a list of all the routes and how they are matched.

Most people create a concept of a `Route` object that contains a predicate, and then you loop over those in a list. It feels super clean. But now if you want an exotic way of matching a particular route, or you want route priority or anything like that, and your route matcher and Route objects start becoming really complex...but if you did it with a simple code block with if statements, it would have been really easy.

    const routes = [ 
      {pathname: '/foo', action: () => {}}, 
      {pathname: '/bar', action: () => {}}, 
    ]
    for (const route in routes) {
      if (route.pathname === request.pathname) { return route.action }
    }
If we could have referenced our if-statement code blocks as a list (using Reflection or something), then we could have avoided any abstraction and stayed totally flexible.

I could easily throw a few more requirements at you, and you would quickly have some frankenstein Route object and matching logic.

It's this weird process of "dont-repeat-yourself" where everything looks the same and you abstract it, and then you realize its not all the same, and instead of back-tracking the data structure, you just tack on new stuff and more complicated logic.

Complexity in software stems from these pre-mature abstractions.

skybrian · 2 years ago
It's not true that everything is a list in most languages. Typically an AST is built with both lists and structs. Special forms are always going to exist and the code needs to deal with them, so this isn't a loss; it's being more explicit. Well-named fields are better documentation and faster than accessing the nth item than a linked list. (You can emulate named fields using just lists, but it's just a convention.)

Also, in most languages, the lists aren't linked lists. They're typically array-backed.

JSON has both lists and objects (which serve as structs) and it's quite popular and usable for representing AST's.

tangentstorm · 2 years ago
Yes but in whatever language you're imagining here, a "list" probably isn't the kind of list that lisp uses (linked lists of cons cells).
habibur · 2 years ago
It's vector and hashmap that you need most, not linked list.
cwicklein · 2 years ago
I had the same thought about conditions a few days ago and discovered this:

https://discourse.julialang.org/t/ann-package-conditions-jl/...

samatman · 2 years ago
Lol. The final domino falls!
CodeWriter23 · 2 years ago
+1 for writing “processing lists” with a lisp
linguae · 2 years ago
Common Lisp once had plenty of backing from major companies like Symbolics, Xerox, and Texas Instruments, as well as smaller companies such as Harlequin. Even Apple owned Macintosh Common Lisp at one point, and SK8 (which could be considered a follow-up to HyperCard) was implemented in it. Had Apple not had its problems in the 1990s, one potential alternate version of Apple I could imagine would be some sort of Lisp OS with a Mac interface (true story: the Newton could’ve had a Lisp OS if it weren’t for C++ advocates winning out). Unfortunately, the AI winter of the late 1980s and 1990s severely damaged the Lisp market; companies either abandoned Lisp or went under. The torch of Common Lisp has been carried on by open source and commercial implementations, but there are no major companies actively backing Lisp in the way that Java is backed by Sun/Oracle and that Python is core infrastructure at countless companies, large and small.

I didn’t know that conferences could potentially generate a lot of revenue to help fund programming language development. I’m quite intrigued by this idea, actually. Thanks to advocacy of the language, there are probably thousands of Common Lisp developers in the world, many of whom are working on interesting projects. Perhaps a series of profitable Common Lisp conferences will provide the spark needed to come up with a modern Common Lisp foundation that is able to support further development of the language.

gumby · 2 years ago
> ...one potential alternate version of Apple I could imagine would be some sort of Lisp OS with a Mac interface...Unfortunately, the AI winter of the late 1980s and 1990s severely damaged the Lisp market...

Your order is messed up: work on Dylan commenced years after that AI Winter had begun.

linguae · 2 years ago
Yeah, I should’ve clarified regarding Apple, which wasn’t in the Lisp workstation market. Apple’s departure from Lisp has little to do with the AI winter (though Hacker News commenters lispm and mikelevins may have a lot more insight given their expertise and the fact that the latter worked on Lisp projects at Apple). Rather, I believe Apple’s departure has to do with Steve Jobs’ return. Apple was an unfocused beacon of innovation in the 1990s, with many competing visions for the future of the Mac and the company. When Steve Jobs returned, the vision became unified under him: the technical underpinnings of the Mac were based on NeXT technology, and other competing visions (such as OpenDoc) were discarded.
hajile · 2 years ago
The saddest thing to me is that Brendan Eich didn't do a scheme like he intended.

If that had happened, the web would have been fast 15 years earlier. Things like Flash wouldn't have ever happened. ES2015 would have never been necessary. HTML would have gone away. CSS would have never existed. Declarative web frameworks would have become a reality decades ago. WASM wouldn't have happened. Even stuff like the App Store likely wouldn't have happened because Scheme would have been fast enough that Jobs would have stuck with his initial web app idea.

BrendanEich · 2 years ago
I don't agree with this counterfactual, much as I love Scheme among languages I've barely used in my career.

Chez Scheme was fast but would not fit in the browser especially on Windows 3.1, which still had the largest share when I started JS in 1995, if memory serves -- it was certainly important to Netscape because Microsoft started bundling IE into later Windows versions, as default browser in Windows 98. Petit Chez Scheme was not fast, and I'm not sure I would have had time to use it in those ten days (I never looked at the code).

Guile was out because of the GPL, not my choice (same as with Make It Look Like Java order) and probably no time to embed, or just no way with 64K segments.

If you know of another fast-in-1995 Scheme that might have fit, links welcome.

binary132 · 2 years ago
None of these "programming language evolutionary fitness retrospective" discussions ever manage to address the real heart(s) of the question:

- UNIX is C, so C-family languages won.

- The network effect is by far the most dominant force in the matter.

All of us would like to believe that we operate in a world where technical merit determines memetic fitness, because our jobs seem to depend on it: after all, if we build good things, we immediately see the consequences, and others must also see and appreciate these consequences, right? By doing well at that, we succeed, right?

Well, it turns out it's not so much like that actually.

NikkiA · 2 years ago
MacOS, with a slight help from MS, very, very nearly tipped the balance to Pascal in the 80s. I dare say that without C++ hitting mainstream around 1990, C would have languished.
kramerger · 2 years ago
Now you are rewriting history :)

Turbo Pascal was responsible for the Pascal success. And then came delphi along and somehow lost against Visual Basic.

zoogeny · 2 years ago
I admit that I haven't touched CL in decades and my most recent exposure to Lisp-ish stuff is writing a bit of Scheme and reading a bit of Clojure (maybe some elisp too).

I like a lot of the ideas behind Lisp-like languages but I dislike writing in them. Parenthesis, as others mention, start to get unwieldy. I often feel like I'm expressing myself "in reverse", almost like I'm programming in Yoda speak. I mean by that, it often feels like I want to edit/add-to the beginning of a statement rather than the ending of it.

Perhaps the discomfort would dissipate with use. But to be honest, I'd rather just grab Python or even Typescript these days for the kind of ease and flexibility where raw performance doesn't matter. And there are other programming languages that excite me more than Lisp (e.g. Elixir, Unison) so my limited free time has plenty of outlets on that front.

What surprises me is that Lisp evangelists have this default assumption that their language ought to be entitled to popularity. They have some kind of "if people only knew" mentality, just like in this article, where they assume that the only reason people don't flock to their language is ignorance. Perhaps it doesn't occur to them that people try it out and then leave and never come back.

derp38726 · 2 years ago
>Perhaps it doesn't occur to them that people try it out and then leave and never come back.

Once the code is data is code clicks there’s no going back. When you read other languages you just see a lisp DSL, you can’t unsee it because you’ve changed.

pests · 2 years ago
Isn't this the exact "if people only knew" attitude he mentioned?
thot_experiment · 2 years ago
Because most programming is done by people trying to do a job and it requires broad tooling support and familiarity, LISP is a language that has neither.

LISP, (similarly to Haskell) requires you to bend your mind and pay an upfront mental cost in order to access it's benefits, which are that everything is equally easy to describe. No construct in LISP feels like it requires you to bend the language in an awful way because LISP is a fantastically generic tool, some things that are common and easy in other languages are more difficult in LISP, but as you get into the weeds building more complex constructs it will never get in your way.

(and since i mentioned it, the benefit of Haskell is that you can make a LOT of statements about your code you know to be true)

JohnFen · 2 years ago
I didn't find Lisp to be particularly costly in terms of mental energy to become competent in. Rust, however, was a heavy lift.

Perhaps different people are inherently more or less compatible with different languages?

shrimp_emoji · 2 years ago
I feel like Rust is easy; it's just responsible, 21st century C code with more data structures in the standard library.

Functional languages are like being forced to fry an egg while on LSD. Eventually, you get the hang of it, and you start seeing Spinoza's God in the form constants, but holy shit was it difficult! It's a totally disorienting and mind-bending challenge of re-learning how to do the most basic things!

AnimalMuppet · 2 years ago
> Perhaps different people are inherently more or less compatible with different languages?

I think this is true. Peoples' minds work differently; different languages fit different minds better.

PaulDavisThe1st · 2 years ago
When I learned emacs lisp back in the mid-80s, I didn't find any requirement to bend my mind or pay any upfront cost. It was a little different from C (and BASIC), certainly, but once I grasped a few basic concepts, it felt extremely elegant and very well suited to the task(s) to which I was putting it.

More recently, I've felt that way about Python, and about a few chunks of my favorite blobs of self-written C++.

agumonkey · 2 years ago
the upfront mental cost debate is still going, a few people tried teachings lisps as first languages and people didn't struggle

i personally cried a few tears when learning java, whereas the weird drscheme class made me all calm and happy

programming also blends a few layers into one, and some people are operating at one (line by line modification of data), some want generic infinite freedom[0], you can rapidly see who will enjoy what there

[0] one trauma i got during studies is failing an exam because after reviewing ada's manual twice, I couldn't find the page explaining the `object'field` syntax and failed not being able to split a string. i never liked ad-hoc syntax much...

WillAdams · 2 years ago
For my comparative programming class in college, I was the only person who got all the Lisp assignments done on time and correctly (it helped that I was deeply into TeX at the time), so there is definitely a mind-frame to be in, and some sort of hurdle which a fair percentage of folks find difficult.

One big problem w/ Lisp is that it is so difficult to distribute programs written using it --- I'd give a lot for the ability to compile to a stand-alone program which could then be distributed.

thot_experiment · 2 years ago
Yeah that's fair, it also came naturally to me but anecdotally I've found a lot of people struggle with it, especially those who came up through a "get shit done first" type python or java pipeline in a traditional institution or bootcamp rather than having a true CS background.
quantified · 2 years ago
Logo was a great teaching language. If you're not already patterned into C-style programming, it is a great experience.
linguae · 2 years ago
Rust requires people to learn how to adapt to Rust’s borrow checker, which can be challenging for programmers coming from other languages, yet this hasn’t stopped Rust’s rapid adoption in systems programming. In fact, Rust’s safety features are Rust’s selling point.

Of course, it helps that Rust came from Mozilla and that it’s used in Firefox. Other than Grammarly and some internal Google products, I don’t know any modern-day high-profile projects written in Common Lisp. What would help bolster Common Lisp would be a high-profile project that would be much more difficult to implement in other languages.

dmz73 · 2 years ago
I find that borrow checked in Rust is the easiest part of the language to get used to. Lifetimes on the other hand seem unnecessary in 99% cases where compiler forces you to use them - why can't it just assume that all the required parts have the 'a and complain if something violates that? Event bigger issue is all the missing features that most other languages have - overloaded functions (they kind of exist in generics), ranged integers, arrays indexed by enums, full support for type aliases, some level of inheritance, even if it was the go style, would make Rust much much easier to use.
tcmart14 · 2 years ago
I'm not sure if Rust is a good comparison though. Rust is a lot closer to C, it is a language influenced by C, and current popular programming languages tend to also be influenced by C. So while there is a lot different with Rust, a lot of knowledge from, lets say, a C developer can carry over.

Say your a C developer, or C++ developer and I am a Rust developer trying to sell you on Rust. You have to learn a new language. No way around it. Even though people may have problems with this statement, at a high level it is close enough, I can sell you on Rust probably by saying, 'it C/C++ with better (subjective) or more modern features and extra constraints (think borrow checker) to guarantee memory safety.' I would not be able to make that same argument with LISP.

The next question could be why this could be true, or more importantly, why are so many people using C-like languages. I'd probably place it on portability and UNIX from when C emerged. And LISP machines died.

In other words, I don't think it would be appropriate to try to draw a comparison between the two with the two of them in a vacuum. If LISP machines survived and were popular today, we could see Rust today having the same popularity of LISP today.

munchler · 2 years ago
I agree with you about the upfront costs. As a functional programming fan (F# in particular), I can’t deny that it sometimes feels like puzzle solving. Fun, but not easy at first.

On the other hand, you can quickly throw together some crappy Python code to do the same thing, but you end up paying 10x the cost over the long run in debugging and rewriting.

So my advice for people who care about the code they write is to pay the upfront cost to do it well. The good news is that the learning curve does get less steep eventually, and at that point you feel like a goddamn ninja.

doug_durham · 2 years ago
Python != Crappy code. Lisp != good code. You can write crappy code in any language. My experience is that it is much less expensive to maintain Python in a team environment in the long run. People aren't tempted to create their own personal "domain specific languages" in Python. Lisp kind of encourages that.
taeric · 2 years ago
This is only true in terms of "free" options. There were (and are?) decent paid options that had quite good tooling. In the free software realm, though, it was lacking.

And... this is kind of the point of the post. The python community doesn't just push to advance only the language, they advance the use of the language in the free software world. What is the closest that the common lisp world has?

BaculumMeumEst · 2 years ago
Package management kind of sucks, the ecosystem sucks, other languages continually improve but nobody will ever advance the CL standard. There is nothing compelling about the language to people who aren't already Lisp people.
siknad · 2 years ago
> There is nothing compelling about the language to people who aren't already Lisp people.

CL is expression based (like Rust, unlike other mainstream languages I've seen), has a concise macro system (more convenient than Rust's imo), has a GC (simpler to use than languages with manual memory management or RC-only), has a better developed ecosystem then some new languages (ex. automatic ffi generation; while buggy, tremendously helpful compared to writing bindings manually). And it's not pure as in Haskell. And it has type annotations that may be checked at runtime or improve performance. An implementation like SICL could make it viable to use it as a scripting language.

Any similar modern languages with better tooling/ecosystem? Perhaps Julia, haven't seen it yet.

vindarel · 2 years ago
For package management, we have:

- Quicklisp, which is pretty handy, since we can install and use a library from the Lisp REPL, without restarting anything.

- Qlot, that installs dependencies locally, and allows to pin them (yeah you can't do that with QL, although cloning a lib and using it is easy).

- ocicl, a new package manager from the world of containers

- CLPM, another new one

- Roswell, if you really really want to install libraries from the terminal (although Qlot does it) or to install implementations, or software.

I bet the ecosystem is bigger than many think: https://github.com/CodyReichert/awesome-cl and anyone would be amazed by its stability.

floren · 2 years ago
Package documentation which seems to mostly consist of a list of variables and function names, possibly with a single sentence describing what the function does. Possibly.
agumonkey · 2 years ago
it's paradoxical since lisp people weren't born this way, surely there was some appeal (beyond being influenced by teachings) ;)
BaculumMeumEst · 2 years ago
I do think there are some traits like curiosity, open mindedness, and patience that make some people more susceptible to infection.
bsdpufferfish · 2 years ago
> nobody will ever advance the CL standard

And that’s a good thing.

BaculumMeumEst · 2 years ago
I suppose, if you are happy with the state of things and the size of the current userbase.
kentrado · 2 years ago
I love programming in common lisp. It has made programming fun again.

I don't know if that makes me a lisp person. I just know it makes programming fun for me.

Lyngbakr · 2 years ago
I'm curious if you can put your finger on exactly why you find it fun?

(While I've never used CL, I do use Clojure and similarly find it huge amounts of fun.)

massysett · 2 years ago
Because I can eliminate drudgery in a way I can understand.

I find that no matter what language I use, I eventually want code that writes code. Other languages have bad tools for this. Sometimes I use an editor, or something else like m4, to generate code.

Haskell has Template Haskell, which is icky in a variety of ways, and it has other stuff that I have a hard time figuring out because I’m not a math PhD.

In Lisp I just write a macro.

Also, I agree strongly with the post below. I like Common Lisp precisely because it is old and unchanging. I like that I can get decades-old used books that are still current. I like that the next compiler version won’t break my code.

https://stevelosh.com/blog/2018/08/a-road-to-common-lisp/

codr7 · 2 years ago
Clojure is a different beast, not better or worse, just different.

CL doesn't have opinions, it's a toolbox.

beanjuiceII · 2 years ago
I love programming in blah. It has made programming fun again.

I don't know if that makes me a blah person. I just know it makes programming fun for me.

samatman · 2 years ago
This sort of conduct isn't welcome here.
kazinator · 2 years ago
Popularity is a matter of luck. But suppose that the forces that drive luck somehow aligned themselves with promoting Lisp. There are ways Lisp would sabotage the luck being radiated upon it.

Programmers who get into CL will hit various silly obstacles:

- No standard way to express special characters in string literals.

- No standard Unicode support; no \u1234 notation in the standard. I/O with character encodings is implementation-specific.

- Weird pathname handling that is simultaneously too abstract, and too nonportable, which is oxymoronic. The pathname abstraction caters to features of operating systems that basically no longer exist. Yet at the same time, two CL implementations on the same modern OS (POSIX or Windows) cannot agree on all the details regarding how a pathname string (the real artifact seen by the OS) parses to a pathname object!

- The experience of just firing up a free CL implementation (no Emacs) out of the box and experimenting in its REPL is poor. CLISP has built in history recall and editing; I would recommend that.

- Ironically poor REPL experience in the free implementations, given that Lisp gave us that word. Only CLISP has built in editing and history recall out of the box. Telling newbies they have to learn a specific editor and its Lisp integration is poor and adds to the activation energy.

- Working with objects can be verbose with syntax like (slot-value point 'x) which is just point.x in many other languages. This can be shortened by defining accessors, but accessors abstract a lot. Given (x point) you no longer know that it's just a simple slot. It's a function call, which could be anything. Another thing is, would you give an accessor a one letter name like x, even if it's in a package?

- Newcomers to Lisp do have to learn the list processing. People coming from languages in which lists are collection bags get confused why their list x is not changing after (append x '(1 2)). If you don't use the loop macro and want to collect items into a list, you have to learn the ritual of push-ing items into a stack, and then using nreverse at the end. Guy Steele described a nice procedural list construction API in Common Lisp, The Language, second edition, but it's not in the standard.

- Working with multiple values is verbose, with forms like (multiple-value-bind (quotient reminder) (truncate 1 2) ...), and multiple-value-setq, and whatnot. Some pattern matching or binding libraries help with that.

dreamcompiler · 2 years ago
> Weird pathname handling that is simultaneously too abstract, and too nonportable, which is oxymoronic. The pathname abstraction caters to features of operating systems that basically no longer exist.

This times 100. There are only a few places where the ANSI standard got it very wrong, but this is one of them. Logical pathnames were intended to abstract away different file naming conventions but what they actually did was cast in stone some anachronisms that are incompatible with modern Unix file naming (e.g. case-sensitive path names. Whoops! Can't handle that.)

The good news is that you can just ignore logical pathnames and use normal native pathnames, or use the illogical-pathnames package which largely fixes the problem.

vindarel · 2 years ago
- (i don't get the first point)

- unicode: major implementations support it.

- oh yeah. UIOP (shipped-in) and libraries fix pathname handling. https://github.com/Shinmera/pathname-utils - https://github.com/fosskers/filepaths - etc

- agreed, it's a pity for SBCL. See https://github.com/lisp-maintainers/cl-repl (although an editor with Slime-like integration is better)

- yeah, it's a choice to make during development. It could be point-x. Or using with-slots.

- yeah

- but multiple values are very helpful (reminder to the reader: they are not like returning a tuple. Return a list if you want). They allow to not break an existing ABI. You can add a return value and not change all the callers. Awesome.

mark_l_watson · 2 years ago
Re: “”Ironically poor REPL experience in the free implementations, given that Lisp gave us that word.””

I just always wrap SBCL, etc. in rlwrap when started on the command line, in fact I alias SBCL to rlwrap <full path to SBCL>.

When I start SBCL in Slime, I use the full path in my .emacs file.

Easy problem to fix.

kazinator · 2 years ago
GNU/Unix command line tool mitigates Lisp problem, in other words.