I've said this before, but I've come to think of Lisp and Forth as the left-handed scissors of software: for 10% of the population they're significantly easier to use, to such an extent that it can feel like a revelation. The remaining 90% of the population tries it, finds it harder to use, and doesn't get why others are raving about it.
This would be down to very fundamental differences in thinking and conceptualisation that are difficult or impossible to "just" teach over. It requires those arguing over "ease of use" to recognise that it's not a property of the tool itself, but a function of both the tool and the user and how well the tool fits the particular, individual, user.
If you've spent years compiling your code and running it or changing it and pressing f5
or changing it and hoping hot code reload does the right thing it won't be apparent why a REPL in process would be helpful
If you've spent years editing your code character by character it won't be apparent why being able to use shortcuts or indentation to edit your code as forms would be a new editing default
I'd argue it's possible to teach everyone, but not motivate everyone
I've also seen a few smart people learn the mechanical parts of Clojure and then dismiss it, not understanding the hype because they were just using it like a very imperative language that just happened to be immutable
Things like lisp, forth and also lambda calculus are conceptually clean. In theory one can write anything in them in a conceptually clean way. However, doing so one has also puts programming and/or computers in a straight jacket which one is going to notice as soon as one wants optimal performance. This is simply not possible anymore. The language that exposes the machine as cleanly as possible is clearly C. But this is not conceptually clean anymore because now one can store information in global variables, on the stack and on the heap. I.e., one has three ways to store values. This is not conceptually clean anymore but it is how one is required to think of computers to do much with them in a performant way. Note that the 'simple' languages actually only expose one of these three concepts to the programmer. In Lisp and the lambda calculus only the heap is exposed and in forth only the stack. In practice, though, implementations of these languages often expose more than what they do in theory. At that point they are no longer clean anymore and I kind of fail to see the point in that case.
> The language that exposes the machine as cleanly as possible is clearly C.
It exposes the PDP-11 most cleanly. For modern machines the mismatch between the C abstract machine and the actual hardware has been steadily increasing for decades. It's still close to the hardware compared to almost all other languages, but it is by no means "as cleanly as possible". It's not portable assembly like in the days of yore.
Common lisp exposes two of these three to the programmer, (stack and heap) and some implementations offer globals as an extension.
A lot of myths about lisp being conceptually pure come from poorly taught college classes. If there were one active lisp user for every time I've heard "Lisp? The only thing I remember about that is that it doesn't have loops," then the lisp community would be a large thriving community.
> The language that exposes the machine as cleanly as possible is clearly C
Well .. sort of. I agree with the comment about C being effectively a PDP-11 VM; there are all sorts of features which it doesn't and can't expose. If you look at the Intel instruction set of the present day with all its extensions, how much of that can the compiler really emit? Multithreading is also something that's been very awkwardly retrofitted to C, with all sorts of memory ordering issues that aren't easy to fix. Then there's all the "undefined behaviour" wrangling.
By raw FLOPS the most powerful part of the average computer will be the graphics card, which really isn't suitable for C (or Lisp!) programming at all.
I'm not sure about 10%. Only a very small fraction of programmers has even ever tried Lisp. That 10% may very well be 50% or even higher. Not that I can judge because I have never tried lisp.
I would be one of your 10%. I have been using Lisp languages since the late 1970s and Common Lisp since about 1982 so I think it is just familiarity.
Another reason could be developers who like to compose programs from the bottom up would naturally like repl based development, but there are many languages with great repl experiences.
What are the fundamental differences that are "difficult or impossible to 'just' teach over"? Looking at a language like Racket, you have classes and objects, (first class) functions, recursion, "for" iteration, threads, mutability, etc. Aren't these features found in plenty of languages?
Anecdotally, there seems to be a dislike of Lisp just because of the parens-based syntax. Do you think the different syntax counts as being such a fundamental difference for 90% of developers? Is it really so bad to have to write:
Racket is not a good example. People learn it as non-interactive. The project now also switches to a conventional syntax without s-expressions.
The big 'problems' are a) interactive use (much of Lisp usage is 'interactivity first'), b) the code as data thing and lack of static feedback (type checks, ...).
The 'code as data' thing is a real hurdle: what is code, what is data, what is transformed code, what are code transformers, ... One needs a mental model to work with code which is making heavy use of meta-linguistic-programming.
> Racket is not a good example. People learn it as non-interactive. The project now also switches to a conventional syntax without s-expressions.
I can understand that people that have achieved "lisp enlightenment" will view Racket this way. With respect to replacing s-expressions, I am hopeful that the original s-expression-based Racket retains prominence even when the Rhombus language is fleshed out. I know I will continue to use s-expressions.
> a) interactive use (much of Lisp usage is 'interactivity first')
To me, having used Clojure (which hopefully counts as an interactive Lisp) and worked in environments like A+ (in the family of APL/J/K), this is an amazing feature and I struggle to see this being such a "fundamental difference ... that is difficult or impossible to 'teach'" (paraphrasing OP).
> b) the code as data thing and lack of static feedback (type checks, ...).
With many people programming in Javascript, Python, and Ruby, the lack of static feedback seems less compelling to me. With "code as data" thing, as a Racket programmer, I rarely if ever think about macros or readers or code transformers. I am sure that can be understood as missing the whole point of lisp, but I have been productive in an environment whose underlying bits can make use of all of that and I can just write code as code and treat data as data in a manner similar to many other languages. Maybe I'm weird, but programming in a manner similar to Java but having code written with s-expressions feels better to me.
Not that much in my view. I don't see Clojure as a particular interactive Lisp, I actually see it only as 'derived from Lisp and others'. 'Lisp' is usually much more interactive, with stateful images (running copies of 'object seas'), mix of interpretation and compilation, interactive error handling, all-layers Lisp (where most of the layers can be inspected/manipulated/changed at runtime, incl. its own implementation) and internal development environments (not externally attached).
The syntax criticism is a red herring in my opinion.
At least speaking personally from my opinion I see a lot of people claiming that lisp simple syntax and homoiconicity make it a simple language and in my opinion this misses completely the point of simplicity in a language.
I am not claiming that lisp is complex, just that that argument is faulty.
That for sure, but what I mean is that syntactic simplicity does not translate to simplicity of meaning.
In the case of lisp and its rich macros system the only thing I can see is that anything could cause any kind of effect; I see this as a significant source of complexity in practice. I am sure that library/implementation authors made a fantastic job in refining wonderful abstraction so that this is not a problem in practice.
Julia offers also has rich macros but there the messaging there is different, macros are intended to be used in library code to allow for greater ergonomics. Users of the language to be able to write an idiomatic library as that involve language features that are not necessary in normal scripting.
(I just now realize that I never heard of an Obfuscated Lisp Contest, things could get quite crazy there)
Have you written lisp code? As a Racket programmer, I almost never think about macros, readers, code transformers, or whatever could interfere with what I think should happen in the same way that I would write Java code. To give an example, the only time I thought macros might be useful was when defining class types (contracts) and default values.
All this would be doing is defining a class with both a type (contract) and a default value without having to first define/contract for types (contracts) and later defining class member defaults.
It's great that Julia has messaging that macros should be reserved for libraries. I can't say that I've seen Racket messaging be the same, but I also don't see a proliferation of macros in libraries that I choose to use for projects, either. Especially in such a manner that makes me concerned that, "will this completely screw up my intention?" If you have a different experience, I am curious to hear it.
> As a Racket programmer, I almost never think about macros, readers, code transformers, or whatever could interfere with what I think should happen in the same way that I would write Java code.
This is exactly what I mean, Racket is not a nice language because it has a minimal syntax, it is a nice language because it is powerful, well thought, and its features work well together. Homoiconicity and macros are tools that Racket uses internally to define itself and they are essential to how many of the language features work, but often they are not directly relevant to the (non-library-writing) user.
Looking at the language is the wrong direction; look at the programmers and how they think, and what people self-report about the ease of use of particular features.
Both left and right handed scissors have blades, a pivot, and handles. The only difference is the arrangement. But remember that both this and the analogy with Maxwell's equations are analogies.
Agreed, and to me, this makes the point that the syntax (arrangement) is a key component to an unwillingness to learn. However, I don't see how this establishes lisp as having, "very fundamental differences in thinking and conceptualisation that are difficult or impossible to 'just' teach over". With left-handed scissors, you have the same concept; you just need to train your left hand to use them. Likewise with syntax. Describing that as being a very fundamental difference that is difficult or impossible to teach over seems odd to me.
I don't think you're getting the example of left-handed scissors; try something like adaptation for red-green colourblindness, where you can't really train around it. Although that's physically based, which is going to be a distraction in the analogy; try the reported observation that some dyslexic people find Comic Sans easier to read.
Or trousers. One size does not fit all.
Or the people discussing the intuitive representation of Maxwells' equations themselves: https://news.ycombinator.com/item?id=23700295 - not everybody likes the equations, some people like pictures for a better understanding, but the equations-first people may not understand that.
This would be down to very fundamental differences in thinking and conceptualisation that are difficult or impossible to "just" teach over. It requires those arguing over "ease of use" to recognise that it's not a property of the tool itself, but a function of both the tool and the user and how well the tool fits the particular, individual, user.