The only feature I am missing in Thunderbird is “group by sender, sort groups by latest receive date in group”. I don’t remember what client I used that had this (outlook, perhaps?) but for me it works so much better than other arrangements:
You still see all the latest correspondence, but also immediately all previous correspondence from the same sender (if you expand the group) whether or not it’s a reply thread.
It’s not very different, but it’s the numpy way is not the math way: when you talk math, you say “the exponent of the absolute value of the cosine of x”, like in APL, not “take x, get its cosine, then take the absolute value, and then get its exponent”
In fact, for many things, you so the math way in numpy as well. But in other things, the dot/object-oriented way is preferred.
APL is just consistent, terse, mathematical notation.
WhatsApp backup on your Google account contains all your message history, and is unencrypted. If you use google cloud backup for your phone, Google can read your WhatsApp messages, and has been able to do so for more than 5 years now.
It is safe to say, optional services get little adoption. Look at email, of the tens of billions of email addresses, there are orders of magnitude lower numbers of pgp or gpg keys. Similar experience with telegram encrypted chats. So having the option of e2ee in a communication platform, is not having it in practice.
One thing humans are good at is pattern recognition. Terse APL is - once you are used to it - very recognizable.
Many constructs take less characters to algorithmically specify than to name: (Examples in K because that’s what I know best):
(+/x)%#x computes the average of a vector x; or the average of each column in a 2D matrix x; or other averages for other constructs. It takes about as much characters to spell “average”, which is considers too short a name in modern C or Java - and yet, the code is instantly recognizable to any K programmer, needs no documentation about how it deals with NaNs or an empty vector or whatever (which your named C/Java/K routine would - does it return 0? NaN? Raise an exception? Segfault?)
And ,// (yes - that’s comma slash slash) flattens a recursive list. Way shorter than its name , and it’s the entire implementation.
Are these the most numerically stable / efficient ways to average or flatten? No. But they are the least-cognitive-load, fastest-to-grasp-and-pattern-match when reading code. Once you are used to them.
The appeal of Iverson languages also comes from a good selection of primitives. Most modern languages such as C++, Python, Nim, even Rust have an implicit focus on the “meta” programming: they give you the tools (templates, macros, classes) to build abstractions, with which you later build your actual computation. K / J / APL / BQN expect you to do the computation with much fewer abstractions - but provide primitives that make that incredibly easy.
For example, there is a “grade” primitive which returns a vector that - if used to index your original list - would sort it.
Now, say you have a list of student names, and ages, and you wish to sort them - once alphabetically, once by age. In idiomatic C++/Python etc, you’d have a “student” class with three fields. Then you’d write some comparator functions to pass to your sort routine. (I am aware of accessors and the key arg to pythons sort; assume for a second they aren’t there).
In K/APL/J, you’d just have 3 lists whose indices correspond: and then it is just:
name[<age]
Read “name indexed by grading of ages”. They’re a terser version: name@<age read: “name at grade of age”
The terseness compounds. Once you are used to it, every other programming language seems so uselessly bloated.
None of these things apply to obfuscated or shortened C.
Arthur released K source code, which is C written in the same style. It does not have the same appeal.
These are all great examples of the advantages of array programming syntax versus imperative scalar programming syntax, but do not IMO demonstrate the advantage of terse array programming syntax.
For example, the NumPy equivalents of your examples are not materially longer than their APL/J equivalents, but are easily readable even by people unfamiliar with NumPy:
> the average of a vector x; or the average of each column in a 2D matrix x
x.mean(0)
or, to use your example verbatim,
x.sum(0)/x.shape[0]
> flattens a recursive list
x.ravel()
> name indexed by grading of ages
name[age.argsort()]
Though for this application, you’d probably be using a dataframe library like Pandas, in which case this would be
You didn’t address points I already raised about mean() - how does it handle an empty vector? How does it handle NaNs ? You have to read the documentation to figure that out. In K, the implementation is in front of your eyes; NaN handling follows from “over” / reduce / addition semantics; and empty vector from reduce and division by zero semantics. It is all consistent by construction, and follows from basic properties. The same cannot be said about mean() or sum().
The call to .ravel() is strictly less powerful than ,// which would flatten a matrix, but also a lisp/xml style recursive list structure. And it is the actual implementation, not some weird name! It is “join over until convergence”.
With respect to sorting, in K you would also likely use the built in relational operator “?” (select).
Notice how you need to import pandas and numpy, and then know their docs well to find the routines you want and how they behave in edge cases? And that’s in addition to actually knowing Python?
K has all of that built in. You just need to know the basics (which takes more work than knowing Python well, admittedly). Most from there is derived by construction. It does have some 80 or so non-trivial primitives, but then you need much fewer libraries, often none.
(And, that’s not a for/against thing, but … in case you wonder, the K executable does that in about 200K binary without dependencies; REBOL achieves similar terseness of final programs by completely different means and philosophy, and also packs that into a 400K executable)
The point is that every idiom beagle3 noted is a simple and straightforward combination of general building-blocks, whereas nearly all of your "equivalents" are a one-off special-cased feature or function that needs to be learned on its own. The power and expressiveness of APL-family languages comes from the fact that they have a very small number of well-chosen parts that can be combined in flexible ways. Those patterns of combination become a higher-level vocabulary that fluent programmers grasp at sight, much as experienced readers of English learn to recognize the shapes of entire words at a time. This type of visual pattern recognition is facilitated by brevity.
APL-style idioms are not at all comparable to functions on a class or within a library, because idioms are self-describing in their entirety, requiring only an understanding of the primitive operators of the language, whereas a named function obscures and subordinates detail.
The spectrum only had one mode: 256x192 1-but pixels, 32x24 palette (each 8x8 box had two colors, “paper” for a 0 pixel and “ink” for a 1 pixel).
Other computers of the time (C64, Apple II, BBC / Acorn) had distinct text vs graphics modes, although some had a user-defined font which kind of makes the distinction less firm.
It’s also hubris and overconfidence. My child had a disease that’s very rare and hard to diagnose. A week at Johns Hopkins with hundreds of thousands of dollars of tests found nothing. The doctors sent us home with a “it’s just a virus, it’ll probably go away in a few weeks”.
Some 72 hours later, armed with google, Wikipedia, the rest of the internet, and coffee (with very little sleep). I figured it out.
But when I called Hopkins they said “you are wrong, can’t be that. Stop using the internet, you have no idea what you are reading and you are only scaring yourself”.
30-or-so specialists from a variety of top US hospitals kept saying the same thing (with the addition: “if Hopkins says you are wrong, you are wrong”.
But then, we saw a specialist in a world top-10 hospital outside the US, who immediately agreed with my diagnosis. Treatment started the following week (only 3 months lost) and the condition started to resolve.
I kept in touch with the doctors I had seen before. They didn’t care. Some thought it was still the wrong diagnosis. Until a year later, near complete remission - and pathology of a resection - confirmed it 100%
Modern medicine is part science, part craft, part cult. You tend to meet the cult aspect more often with rare or hard-to-diagnose diseases.
> But when I called Hopkins they said “you are wrong, can’t be that. Stop using the internet, you have no idea what you are reading and you are only scaring yourself”.
I am sorry to hear that. This is the path once upon a time I would of taken. Just assuming it was bad to be Dr Google as I'd learned from a young age. Let the doctors do their job and all that. Now I am the complete opposite.
My neurosurgeon HEAVILY pushed me to start "googling" and "reading whatever you can" and straight up told me not to trust general practitioners as the vast majority of them are woefully ill equipped to deal with anything I am dealing with.
Thank god I took his advice, because I almost did the same thing again. For months GP's were telling me my new and expanded pain was the same old SCI injury "flaring" my CNS, and that I should just take more drugs/do more physio and literally I got asked "what do you want us to do? Take the painkillers like we do told you"
Well, three specialists (and two neurosugeons later) its NOT the existing injury, its severe bilateral cervical radiculopathy from where my cervical spine is disintegrating on the layers above and below my original fusions and its not going to magically get better by throwing even more drugs at it, or moving my physio sessions from 3 times a week to 5 times a week.
Once upon a time, I would never have said this, not deeming myself to know enough to possibly say it, but I have met now a lot of very useless doctors, like just outright incompetent.
I was amazed by Bill's software seeing it on a Mac back then - MacPaint mostly, then HyperCard. I was not even 10, but I was already programming, and spent hours trying to figure out how to implement MacPaint's Lasso on my humble ZX Spectrum. (With some success, but not quite as elegant...)
If you want to experience HyperCard, John Earnest (RodgerTheGreat on HN[0]) built Decker[1] that runs on both the web and natively, and captures the aesthetic and most stuff perfectly. It uses Lil as a programming language - it is different than HyperTalk, but beautiful in its own right. (It doesn't read as English quite the way HyperTalk does, but it is more regular and easier to write - it's a readable/writable vector language, quite unlike those other ones ...)
Can't give a definitive answer but my allow/deny list parser has always used `MIME::QuotedPrint` through `html2text` to convert them from MIME'd HTML into plain text and that was last updated September 2021.
I've also got a test note from late 2020 which is also `text/html; quoted-printable` which suggests at least iOS 14 (I don't think the 15 alphas would have been out by then.)
You still see all the latest correspondence, but also immediately all previous correspondence from the same sender (if you expand the group) whether or not it’s a reply thread.
reply