Interesting story. I am not entirely convinced that all credit should go to the programming language here, though.
My theory is that communicating abstractions is hard. If you work on your own, or in a (very) small team, you can come up with powerful abstractions that allow you to build amazing systems, quickly. However, sharing the underlying ideas and philosophy with new team members can be daunting. As systems grow, and mistakes are made, it becomes more and more likely that you run into serious problems.
This may also be why Java and similar object oriented programming languages are so successful for systems that have to be maintained for ages, by large teams of developers. There are but few abstractions and patterns, and it does not allow you to shoot yourself in the foot, nor to blow your whole leg off. Conversely, this may also be why complex frameworks, such as Spring, are not always so nice, because they introduce (too?) powerful abstractions, for example through annotations. It may also clarify why more powerful languages such as Scala, Common Lisp, Smalltalk, Haskell, etc, consistently fail to pick up steam.
Another theory is that not every developer is comfortable with abstract concepts, and that it simply takes a team of smart people to handle those.
> It may also clarify why more powerful languages such as Scala, Common Lisp, Smalltalk, Haskell, etc, consistently fail to pick up steam.
Languages need a window of opportunity, and many of those squandered it.
Clojure won over Scala because at the time when people were loooking for an alternative JVM langauge, Clojure was more of a departure from Java and seemed to have better tooling (compile times and syntax support) than Scala.
Smalltalk and Common Lisp wasted their moment by not being cheap/free to people using micros in the 1980s.
Lisp, especially, very much wasted its moment with micros. The fact that no Lisper had the vision to dump a Lisp onto the bank switched micros (which makes GC really easy and useful) of the mid to late 1980s is a self-inflicted bullet wound. Lots of us hated doing assembly language programming but had no real alternative. This was a loss born of pure arrogance of Lispers who looked down on those micros as not being "real machines".
I weep for all the hours I wasted doing assembly language as a teenager that I could have been writing Lisp. How much software could have been written that would have been <100 lines of Lisp if only someone had written that tool?
...in what sense has Clojure actually won over Scala?
I see way more Scala in companies last ~5y and have the impression of its ecosystem being more robust. Not uncommon for greenfields. It's longer than that I even encountered an active Clojure codebase. This is from a data-engineer perspective.
Clojure may be more popular for some niche of app startups perhaps? We are in different "bubbles" I suppose.
I can't really speak to modern stuff, and it is certainly possible my memory is faulty. Scala was a PITA in the early 2000s and you were generally better served with something else if you could move off the JVM. Clojure came in about mid 2000s and seemed to be what a bunch of people stuck on the JVM but doing data processing were desperate to find.
My feeling was that a lot of Clojure folks moved on as the data processing stuff moved on from Java/JVM.
My impression has been that JVM-based languages have effectively been on a steady general decline for a while now. Java has fixed a lot of its issues; Kotlin gave the Java expats somewhere to go. And Javascript/Node along with Go drained out the general masses who didn't really want to be on the JVM anyhow.
However, it is interesting that Clojure has effectively disappeared in those rankings.
Lisps really only come into their own above a certain size/amount of resources. For early Lisp the PDP-11 with 2-4 MB RAM was considered to be nice. There were some Lisp implementations for the PCs but they suffered from the need for compatibility with older hardware.
The bank switched memory architectures were basically unused in mid 80s micros (C128, CoCo3, etc.).
Lots of utility software like spell checkers and the like still existed. These would be trivial to implement in Lisp but are really annoying in assembler.
Lisp would have been really good relative to BASIC interpreters at the time--especially since you could have tokenized the atoms. It also would have freed people from line numbers. Linked lists work well on these kinds of machines. 64K is solid for a Lisp if you own the whole machine. You can run over a bank of 16K of memory for GC in about 50 milliseconds or so on those architectures.
Had one of the Lisperati evangelized Lisp on micros, the world would look very different. Alas, they were off charging a gazillion bucks to government contracts.
However, to be fair, only Hejlsberg had the correct insights from putting Pascal on the Nascom.
> Lisp would have been really good relative to BASIC interpreters at the time
I see no evidence for that. Lisp was a pain on tiny machines with bad user interface.
> 64K is solid for a Lisp if you own the whole machine.
I had a Lisp on an Apple II. It was a useless toy. I was using UCSD Pascal and Modula 2 on it. Much better.
I had Cambridge Lisp on an Atari with 68k CPU. It was next to unusable due to frequent crashes on calling FFI functions.
The first good Lisp implementation I got was MacScheme on the Mac and then the breakthrough was Macintosh Common Lisp from Coral Software.
> Had one of the Lisperati evangelized Lisp on micros
There were articles for example in the Byte magazine. Lisp simply was a bad fit to tiny machines. Lisp wasn't very efficient for small memory. Maybe with lots of work implementing a tiny Lisp in assembler. But who would have paid for it? People need to eat. The tiny Lisp for the Apple II was not usable, due to the lack of useful programming environment.
> Alas, they were off charging a gazillion bucks to government contracts.
> There were articles for example in the Byte magazine.
And they were stupid. Even "good" Lisp references didn't cover the important things like hashes and arrays. Everybody covered the recursive crap over and over and over ad nauseam while people who actually used Lisp almost always sidestepped those parts of the language.
> I had a Lisp on an Apple II. It was a useless toy. I was using UCSD Pascal and Modula 2 on it. Much better.
And yet UCSD Pascal was using a P-machine. So, the problem was the implementation and not the concept. Which was exactly my point.
> At least there were people willing to pay for it.
Temporarily. But then it died when the big money went away and left Lisp all but dead. All the while all the people using languages on those "toys" kept right on going.
> And yet UCSD Pascal was using a P-machine. So, the problem was the implementation and not the concept. Which was exactly my point.
My point is that implementations don't come from nothing. You can't just demand them to be there. They have to be invented/implemented/improved/... Companies at that time did not invest any money in micro implementations of Lisp. I also believe that there was a reason for that: it would have been mostly useless.
> Temporarily. But then it died when the big money went away and left Lisp all but dead. All the while all the people using languages on those "toys" kept right on going.
This has actually been my experience. When I started with Clojure I was writing it badly. I came from NodeJS world. It even took me a week's time just to setup the working environment.
With time you get to understand the power of simplicity. How to break the problem and compose the solutions to achieve your intended result..
Another theory is that C inspired languages are very mechanistic and easier to visualize. Same goes for OOP with the Animal->{Cat,Dog} explanation. But that's just surface level and once you get to the difficult part (memory management in C and software design in Java) where the ability to grasp abstractions is required, we're back to square one.
I believe once you've got to some point, dealing with abstractions is a way of life. It's either in the language, the technical requirements, or the software design.
"Objects are the way we think" is one of the largest design traps ever laid in software development. Because if you design your program like it, unless in certain special circumstances, it will be shit.
There's the way we think about the problem and it's solution and there's the way that the machine can execute these solutions. More often there's no direct mapping other than a tower of abstractions. The issue is that the problem and our model are too fluid and it's best not to rely that much on a certain paradigm.
Powerful abstractions tend to come back and bite you a few years later when the industry trends shift and everyone else starts using a different set of abstractions. Now that small team is stuck maintaining those custom abstractions forever and is unable to take advantage of new abstractions from vendors or open source projects. So their progress stagnates while competitors race ahead. I've been on the wrong side of that before.
> object oriented programming languages are so successful for systems that have to be maintained for ages,
ehmmm.... excuse me.... erghmm... what about Emacs? I'm sure, it absolutely can be count for a "successful system that have to be maintained for ages". For far, far longer than any Java-based project that ever existed.
Even though Elisp lacks:
- static typing
- OOP class system (until relatively recently)
- Modern package management (until ELPA/MELPA)
- Multi-threading model
- JIT compilation
Perhaps "the secret sauce" of successful software is in simplicity? Maybe some programmers just get it, and for others, it is such an obscure and mysterious entity. Some programmers write "programs to program computers", and some may have realized that they are not trying to solve purely technological problems, but they are, in fact, tackling socio-technological problems, and they write programs to communicate their ideas to fellow human beings, not machines.
I've been using emacs for over 10 years. Maybe close to 15. I can't get rid of it, because even for all its faults, I love it. I'm hopelessly stuck with it.
However, emacs is a fucking mess, and there is a reason "init.el bankruptcy" is a thing and why the most popular way to use emacs is through various frameworks such as doom or spacemacs.
In emacs, nearly everything can(and often does) mess with everything else. It is serious integration hell to actually get things to work together, and the work that goes into e.g. doom is basically all about managing that complexity through good abstractions and more rigid ways to configure and install things.
Emacs is also objectively dogshit in a lot of ways compared to most modern editors. LSP is ridiculously slow and a constant source of performance issues, many of which are probably directly related to emacs internals. Eglot seems to do better but it's a lot more limited(you can't use multiple language servers together, for example). Then there's things like the buffer being the data-structure for everything, which is sort of like modeling nearly everything as one long string. Things that would be trivial to do in most other languages or contexts are difficult and error-prone in emacs.
> Emacs is also objectively dogshit in a lot of ways compared to most modern editors
Yet not a single modern editor can even come close to it when it comes to extensibility and customization; self-documenting; complete programmability; malleability; ability to perform virtually any computing task without leaving the editor. Modern editors excel at being user-friendly out of the box. Emacs excels at becoming exactly what each user needs it to be. While you find yours to be "objectively dogshit" in comparison, I can probably easily demonstrate to you how mine eats their "modern" shit without even chocking.
> LSP is ridiculously slow
Have you tried to get to the bottom of it? Sometimes it just the lsp-server implementation that is slow. Have you tried https://github.com/blahgeek/emacs-lsp-booster? Did you build Emacs --with-native-comp flag? Have you tried using plists for deserialization https://emacs-lsp.github.io/lsp-mode/page/performance/#use-p...? Have you used Emacs' built-in profiler? Sometimes the issue might be somewhere else, e.g., some fancy modeline settings.
> Things that would be trivial to do in most other languages or contexts
Sure, that's why we see so many "Emacs killers" built in Java, because replicating Org-mode is so trivial in it. /s
Yes, I've wasted a considerable amount of time trying to get to the bottom of the performance problems. So have multiple other avid emacs users I know that regularly have to deal with these problems. One of them is trying to live with eglot because it feels a lot faster - now they are also trying to use a sidecar process multiplexer to support multiple language servers. This is like the emacs experience in a nutshell.
My conclusion is basically: some language servers are slow, which doesn't help, and some are also very noisy. Both scenarios are handled extremely poorly by emacs, i.e. locked ui when parsing or waiting sometimes, stuff like that.
You really have to be a special kind of oblivious to argue so vehemently while literally suggesting I run a separate program on the side to get what most would consider to be a basic, functioning editing environment.
Re the org-mode argument: I really think you mistake lack of interest for insurmountable complexity. Emacs is not a magic machine that can do things no other software can do. You can probably count the number of people who genuinely care about org-mode in the world on 10 sets of hands.
Okay, I'm just trying to help. I, for one, don't experience extremely vexing problems with performance like you're describing. But of course, I'm not going to pretend that I'm unaware that Emacs needs to improve on that front, and over the years there have been numerous improvements, so it's not a completely hopeless situation.
> basic, functioning editing environment
Different priorities. For me, "basic, functioning editing environment" means stuff like indirect buffers - which not a single other modern, popular editor offers.
> Emacs is not a magic machine that can do things no other software can do.
In some cases, it literally feels exactly like that. So while not literally magical, Emacs enables workflows and capabilities that can feel transformative and, yes, almost magical to its users. The "magic" comes from its architecture and philosophy. I can easily list dozens of use cases I've adopted in my workflow that are simply impractical to even try to replicate in other editors.
One can criticize pretty much any software product. Yet Emacs still falls in the category of "successful systems that have been maintained for ages". Anyway, we're getting sidetracked. My main point in the comment wasn't about Emacs, the main point is in the last paragraph. Maybe you just didn't even get to it.
It's embarassing to have to even say this , but a counterexample, or even a few, does not invalidate the argument. You would need some sort of representative sample of successful projects, and then figure out which paradigm was used for each one and see if there's any statistically significant pattern. Good luck doing that reliably though.
While focusing on the first part of my comment it seems you completely ignored the [main] point in the last paragraph.
All programming languages are man-made, human constructs and not a single one is the most ideal for the task of programming - just like not a single spoken language can claim absolute superiority for communication. The nature of programming often eludes clear categorization, challenging us to define whether it belongs to the domains of art, business, or engineering. Maybe it's all of these? Maybe it's none of it? We, programmers endlessly engage in passionate debates about language superiority, constructing complex arguments to defend our preferences. I'm not a musician, but can you imagine guitar players vehemently arguing with drummers that guitars are ultimately better instruments because, I dunno, one never can perform Für Elise using drums. And then some experienced drummer comes and performs it in way no one ever imagined. I think, the beauty of programming, like music, lies in its diversity. Instead of engaging in futile debates about superiority, we should celebrate how different languages and paradigms enrich our craft, each bringing its own unique perspective and elegance to the art of problem-solving.
One of the things I feel grateful for after learning Clojure is that many, perhaps most people in the community are genuinely experienced, seasoned software developers, driven to Clojure by curiosity after many years spent in other programming languages. Clojure allowed me to fall in love with my trade once again. The combined malleability of Lisp that can emulate (almost) any known programming paradigm and the simplicity and data-centric design in Clojure helped me (truly) understand the core principles of programming. Ironically, after using numerous different languages for many years, spending years of grokking their syntactic features and idiosyncrasies, many stackoverflow threads and tutorials later, only after switching to Clojure did I feel like I understood those languages better. One peculiar aspect about Clojurians, that they don't typically engage in general debates about programming languages without specific context, subtly breaking the famous Perlis quote about Lispers knowing the value of everything and cost of nothing. Clojurians known for their grounded perspective and non-dogmatic approach to problem-solving. So, they typically don't bash on someone else's favorite language, instead they'd try to learn and steal some good ideas from it.
My theory is that communicating abstractions is hard. If you work on your own, or in a (very) small team, you can come up with powerful abstractions that allow you to build amazing systems, quickly. However, sharing the underlying ideas and philosophy with new team members can be daunting. As systems grow, and mistakes are made, it becomes more and more likely that you run into serious problems.
This may also be why Java and similar object oriented programming languages are so successful for systems that have to be maintained for ages, by large teams of developers. There are but few abstractions and patterns, and it does not allow you to shoot yourself in the foot, nor to blow your whole leg off. Conversely, this may also be why complex frameworks, such as Spring, are not always so nice, because they introduce (too?) powerful abstractions, for example through annotations. It may also clarify why more powerful languages such as Scala, Common Lisp, Smalltalk, Haskell, etc, consistently fail to pick up steam.
Another theory is that not every developer is comfortable with abstract concepts, and that it simply takes a team of smart people to handle those.