Some of it I recognize as being an artefact of the time, when conciseness really mattered. But it's still obnoxious in 2025.
The whole thing reminds me of D&D, which is full of classes & spells that only exist in modern D&D because of One Guy who happened to be at the table with Gygax, who really wanted to be a wuxia guy he saw in a movie, or because he really wanted a spell to be applicable for that one night at the table, and now it's hard-coded into the game.
Perl has always “flowed” for me and made mostly intuitive sense. Every other language I’ve had to hack on to get something done is a struggle for me to fit into some rigid-feeling mental box.
I understand I’m the weird one, but man I miss Perl being an acceptable language to pound out a quick program in between “bash script” and “real developer”.
> in between “bash script” and “real developer”.
One of my coworkers gave me some great perspective by saying, "at least it's not written in Bash!"
It certainly was the major factor in how I connected the dots!
Haven’t really thought about it until now, but I suppose having Larry Wall and Randal Schwartz telling you to RTFM guides your early development in a certain manner.
I certainly have never considered myself a developer or programmer though. I can pick up enough syntax to get a quick hack done or start a MVP to demo my ideas, but I leave the “big boy” dev stuff to the professionals who can run circles around me.
I'm sure there are people who started in a language and later found something that made more sense. I'm just reflecting on what I've found in my experience.
When at University the academic running the programming language course was adamant the Sapir–Whorf hypothesis applied to programming language. ie language influences the way you think.
Chet Ramey became the primary maintainer of Bash in the early 1990s and is the sole author of every bash update (and Readline) since then. That would be an enormous task for a team of 100, no less a team of one.
I've become quite a fan (after struggling mightily with its seemingly millions of quirks.
I write bash scripts only because I can rely on it being there.
This, it was very unixy and felt like a natural progression from shell scripting. I think that's why a lot of early linux adopters were so enamored.
On the other hand, I was able to easily pick up just about any "tradional" language I tried--from Basic and C in the 80s all the way to Dart and Go more recently.
Or doing a plain set of scripts into a repo, instead of endless arguments how fit a module implemenents the onion and hexagonal architectures, clean code, or whatever is the trend in this year's architecture conferences.
It lets you write shell scripts with clojure. Babashka itself is a single executable, so no JVM bulk or startup time. And the built-in libs include all sorts of nifty utilities. Parsers, servers, excellent async stuff (but IMO clojure might have the best async story of any language out there so I’m biased), http stuff. All macro-able and REPL-able and everything. It’s a scripting dream, and when it’s time to be an adult, you can throw it on the JVM too!
Also… a lot of that complexity is essentially self-inflicted.
I must say however: “devops” is completely different from what old-school system administration used to be.
Also the culture wasn’t hostile to me as a newcomer. The Perl books I read encouraged not writing overly terse, cryptic code, and I got helpful answers via mailing lists.
I still use Perl sometimes if my command pipeline gets too complicated.
YODA: No... no... no. Quicker, easier, more seductive.
LUKE: But how will I know why Python is better than Perl?
YODA: You will know. When your code you try to read six months from now.
> "A lot of the mystique of APL is because it's illegible ... nothing more than a DSL for 'numpy-like' code. .. same demo, using Julia and the result is (in my opinion) much more legible: ... let n=sum(map(
sum() in Julia is more clear and more readable at a glance than +/ in APL, but the APL version is a combination of two things. + which is a binary addition function, and / which is reduce, a higher-order operator or meta-function. sum() in Julia doesn't lead you to think about anything else except what other builtins exist. The APL notation leads you to wonder about combining other commands in that pattern, like times-reduce is ×/ and calculates the product of an array of numbers. From the notation you can see that sum and product are structurally related operations, which you can't see from names sum() and product(). Then you change the other part by wondering what plus does if used with other higher functions, like +\ (scan) and it's a running-sum across an array. (i.e. "+\ 1 1 1 1" gives "1 2 3 4", the sum so far at each point).
So the notation isn't just about readability, it's a tool for thinking about the operations. Different notations enable you to think about different things. If we imagine there was no sum() then you might write:
sum = 0
foreach (n in numbers) { sum += n }
product = 0
foreach (n in numbers) { product *= n }
and whoops that doesn't work; this notation brings to the focus that sum has to start with 0 and product has to start with 1 to get the right answer and you can wonder mathematically why that is; APL notation hides that just like it hides the looping. Different notation is a tool for changing the what people think about - what things we must attend to, cannot attend to, and what new things a notation enables us to see. dTal's next reply:> "the power of abstraction of APL is available to any other language, with the right functions. ... there's nothing to stop anyone from aliasing array-functions to their APL equivalents in any Unicode-aware language, like Julia (oddly, nobody does)."
Maybe nobody does it because if you can't take the patterns apart and put them back together differently without an APL engine behind it, is there any benefit? Take an example from APLCart[2]:
{⍵/⍨∨\⍵≠' '} Dv # Remove leading blanks [from a character vector]
In C# that task is str.TrimStart() and I assume it's a loop from the start of the string counting the spaces then stopping. Calculating length - num_of_spaces, allocating that much memory for the new string, copying the rest of the string into the new memory. I wouldn't think it was do-able using the same higher order function (\ scan) from a running sum. What this is doing to achieve the answer is different: {⍵≠' '} ' abc def' # make a boolean array mask
┌→──────────────────────┐ # 0 for spaces, 1 for nonspaces
│0 0 0 1 1 1 0 0 0 1 1 1│
└~──────────────────────┘
{∨\⍵≠' '} ' abc def' # logical OR scan
┌→──────────────────────┐ # once a 1 starts,
│0 0 0 1 1 1 1 1 1 1 1 1│ # carry it on to end of string
└~──────────────────────┘
{⍵/⍨∨\⍵≠' '} ' abc def'
┌→────────┐ # 'compress' using the boolean
│abc def│ # array as a mask to select what to keep
└─────────┘
Now how do I remove the leading 0s from a numeric array? In C# I can't reach for TrimStart() because it's a string only method. I also can't assume that there's a named method for every task I might possibly want to do. So I have to come up with something, and I have no hints how to do that. So I have to memorise the TrimStart() name on top of separately learning how TrimStart() works. That notation gives me a clear readable name that isn't transferable to anything else. In APL it's: {⍵/⍨∨\⍵≠0} Dv # Remove leading zeroes [from a numeric vector]
That's the same pattern. Not clear and readable, but is transferable to other similar problems - and reveals that they can be considered similar problems. In C where strings are arrays of characters, you aren't doing whole array transforms. In C# strings are opaque. In APL strings are character arrays and you can do the same transforms as with numeric arrays.Which part of that would you alias in Julia? I suspect you just wouldn't write a trimstart in this style in Julia like you wouldn't in C#. You wouldn't think of using an intermediate boolean array.
It's not just about "readability", the APL notation being concise and self-similar reveals some computy/mathematical patterns in data transforms which "giving everything a unique English name" obscure. And APL notation hides other patterns which other notations reveal. i.e. Different notations are being tools for thinking differently about problems, Notation as a Tool for Thought.
+ - * / and other operators work not only on numbers but on strings, arrays and other types and all have an intuitive application.
on strings and arrays for example, + is concatenate, / is split, * is join, - is filter (with static values).
That's so funny to me; I like Python, and dislike Perl & Ruby. Something about Ruby rubs me the wrong way - I could name a few things that I think are _objectively_ bad decisions in the language's design, but it's mostly about an aesthetic preference that's just a matter of taste.