The series is over, and like any big project, it's time for a retrospective.
I did very little. After I finished 100-episode "Electron Adventures", I had a few ideas what to do next, and I went with "100 Programming Languages Speedrun".
I didn't have a list of languages to cover except literally first two (Python and Emojicode), and I didn't know what format to use. As far as I know, nobody really did anything similar before, at least not a whole 100.
One thing that was clear to me from the start, was that I had no intention to fanboy 100 languages. There's thousands of programming languages, most languages are trash, most of the rest is obsolete, and even the ones which still are usable have a lot of issues. I think a lot of people were shocked by this style. Somehow harsh reviews of movies, books, or games, are completely commonplace, but harsh reviews of technology are very unusual.
The format established itself fairly quickly. I wanted to highlight what the language looks like on some simple examples, any issues you'd run into in first days of coding, and a few cool or unusual things the language does.
I repeated the same examples of FizzBuzz, recursive Fibonacci, Unicode handling, structural equality, console.log etc. a lot of times, as shocking number of even modern language really struggle with that. I'm not sure if varying it a bit would make the series more interesting.
I started doing Wordle only in episode 85, and in retrospect that would have been a far better test case, as it does so many things - file input, user input, string operations, randomness, two types of looping, if/elsif/else chains, Unicode printing etc. all in one small package.
The Big Thesis
It's easy to dismiss a lot of my criticism as nitpicking minor things, as almost all of them have some workarounds, and experienced programmers know the workarounds. In many cases I know the workaronuds I well, I just went for the simplest things, and watched it burn.
My Big Thesis for this series, and it's something that cannot really be proven, is that a language that has a lot of issues with very basic stuff, is going to have even more issues the deeper you go. And the language where everything goes smoothly, will likely keep going smoothly.
This isn't some universal truth, for example if you tried to do a similar series on a Windows computer, you would rate a lot of languages Trash, because Windows support is often very poor for even otherwise very good languages. And if you tried it on your phone, it would be even worse.
But I think the things I tried were very basic things, and we should expect all languages to get them right.
All code I wrote for this series is on github. I also generally specified if you can just
brew install the language, or if you need to do some special steps to get it running.
Of course that penalizes any language that doesn't have easy installation on (x86-64) OSX, but they fully deserve it.
I was looking into languages which I found interesting, and felt zero obligation to cover something just because it was popular.
At first I had an abundance of languages to choose from, but from about halfway finding good languages was more and more of a struggle, and I spent far too much time going through Rosetta Code, Esolangs Wiki, and Google to find something interesting.
There were a few categories of languages that I really wanted to explore, and I think I covered this space quite well:
- alternative Unix shells
- early languages before the Perl/Python/Ruby era, especially early Unix languages
- JVM languages
- Lua VM and "alternatives to Lua" embedded languages
- modern Lisps
- non-English-based languages
- parser generator languages
- Ruby-inspired languages
- Smalltalk-inspired minimalist languages
I also did a few scientific languages, a few Forth-likes, a few assemblers, a few esoteric languages. There were a lot more, but it didn't seem too interesting to continue.
Languages Not Covered
There were a few reasons why many languages were not covered:
- I just finished 100-episode "Electron Adventures" and I really had enough of the frontend - otherwise there would be many such languages, as that's very active space
- a shockingly high number of languages just wouldn't run on my OSX laptop, or had too many technical issues. Notably anything with .NET was just too much pain (I especially wanted .NET assembly).
- a few languages (like APL and Brainfuck) I started writing about, but it felt like there's no way to cover them meaningfully in a reasonably sized episode - the "one per day" format was not kind to them
- sometimes I started checking out a language, but it was just too boring - for example most non-English languages turned out to be just "Python with some keywords replaced" or such
- a lot of language categories (like the whole C/C++/Rust style languages) I simply wasn't interested in all that much, and they're really judged by criteria (performance, portability, etc.) very different from how I judge languages (productivity, good design, programmer hapiness). The whole category would be "Hello World takes 10 lines, instant Trash tier" if I used the usual criteria.
I tried multiple times to include some APL-style languages, as they're an interesting piece of history, but the whole APL world is a mess. GNU APL is godawful, most newer APL-likes are proprietary, or don't run on modern systems, or are linked with some specific databases, and difficult to run standalone. I was definitely surprised by this.
Advice for Bloggers
If you want to do something like this, I'd recommend much lower target than 100.
100-episode Electron Adventure worked because whenever I did something complicated, I'd just split that into 2 or 3 small episodes, and that was all perfect. With this series the whole language had to fit an episode, and on top of that I spent a lot more time just finding potential languages, trying to get them running, trying them out etc. - only to discard a lot.
I didn't measure it too precisely, but I'd say my Electron Adventure series was about 2h/episode, and this one was more like 5h/episode.
I'd recommend something smaller like "20 Languages in 20 Days". That's enough to cover a lot of languages, without it taking over your whole free time. Definitely pick languages that seem interesting, don't follow any popularity list. And for the way to test the languages, some simple game like Wordle seems like a great way.
Advice for Language Designers
After reviewing so many languages, I think I can see some patterns:
- your language should be installable with
brew install <language>or
pip3 install <language>or some single command
- if it makes any sense at all, your language should support
#!- even many languages which don't expect this to be the main way to use them still support this, and it's great
- it's 2022, just support damn Unicode fully
- even phones people throw away after two years have 64GB or more, extreme minimalism is silly
- if you don't know any better, just copy full set of methods for standard library classes like string, array etc. from Ruby or something (or from Python, but only if you support list comprehensions). It's cringe that we still have to manually write such extremely basic stuff.
Some features are huge winners. So many languages started without them, and then added them, and the biggest winner is - string interpolation. It's difficult to imagine any language where string interpolation wouldn't be useful.
Two other notable winner features are:
_separators in long numbers (so you can write
500000000and forcing programmer to count the zeroes)
- precedence of operators (so you can write
1 + 2 * 3instead
(1 + 2) * 3)
It might sound surprising that I mention the last one, as all current mainstream languages have operator precedence, but people keep coming with minimalist languages that just go "oh everything evaluates left to right". Smalltalk notably did this, and every single Smalltalk-derived language had to revert that nonsense.
There are also features which keep showing up, but they're total losers, and every single language which tried them ended up reverting them:
- dynamic scoping
- prototype-based OOP
Dynamic scoping is mostly a side effect of the easiest way to do scoping in Lisp. You'll sort of do this by accident if you're not careful. Outside Lisps it's very rare. Dynamic scoping is arguably fine when explicitly requested (as in Perl, Raku, and as can be emulated in Ruby), but it's a ridiculously bad default.
As for prototype-based OOP, Smalltalk tried it, and Smalltalk-derived languages generally reverted to class-based OOP.
It seems like that same story is happening the third time with Lua - big selling point of LuaVM languages I reviewed was class-based OOP.
I don't think there was ever anything in the whole history of programming as overwhelmingly rejected as prototype-based OOP.
And I didn't review this, but the third huge loser are checked exceptions from Java. It was the dumbest Java feature, every other JVM language decided to not have thew, .NET decided to not have them, and every Java library that's not made by total idiots dropped them, even the ones that initially used checked exceptions. Fortunately this is a lesson that was learned fast enough, and it's almost unheard of outside legacy Java code.
I plan to take a break from daily blogging. I'll definitely do more series in the future, but they'll likely be much shorter.
Top comments (4)
Swift surprised me - it’s a pretty elegant language with a few unique characteristics (and noticeable Ruby influence). And it works shebang-style too despite being compiled. The standard library has a few deficiencies around string handling though - my main complaint being
I really wanted to like Rust. Perhaps if I made a bigger investment than a half dozen Advent of Code problems, I’d get the hang of it. Philosophically it’s unlike any other language I’ve used. Its type inference is smart. Its move semantics are unique. But it feels so incredibly cumbersome to get things done with it. Swift made much better choices with regard to optionals.
Looks like you missed Rust, it stands out and I bet you'll like it, definitely worth checking! Main focus is on safety, so perhaps it's less productive than languages which don't care, but as for good design and programmer happiness - it is the best.
I agree on Rust, it's pretty thoughtfully designed, has pretty decent type inference and sane defaults.
Has algebraic data types which I find quite helpful on the productivity side (they may slow down writing some code, but make it faster to write correct code)
There's one caveat: the borrow checker has a steep learning curve.
for the recors, ABAP has checked exceptions too.
Has unchecked ones too, and I stick to those whenever I can choose to