Tuesday, August 20, 2024

Objective-C is just, like, a leaky abstraction over C

Recently I came across this 10 year old post by Robert Atkins: Objective C is like Jimi Hendrix. It is about reconciling admiration for Objective-C by the "old-timers" with the newcomers' somewhat less enthusiastic response.

His very cogent insight was that Objective-C, like Jimi Hendrix, introduced new concepts that were somewhat revolutionary (""mind blowing") at the time, but are now taken for granted:

So if you'e new to Objective-C and, as I am, struggling to come to terms with the fact that it's one great big leaky abstraction on top of C, put yourself in the shoes of an 80s C programmer and remember you get to use these neat "modern" features in a systems programming language.
As one of the very early, pre-NeXT, adopters of Objective-C, I have a slightly different take: That implicit "despite" is actually very much a "because" for me.

The modern features in Objective-C such as a dynamic messaging, a runtime with introspection and intercession etc. were not new at the time, and they were not really "mind-blowing". LISP and Smalltalk had had them for a long time. But so far having these features had required large, complex runtime environments that were very distant from the rest of the machine, and usually quite isolated from the rest of the machine. Still are, to this day. You don't program your computer with LISP or Smalltalk. Your computer runs a separate LISP or Smalltalk computer that you can then program on its own terms and in its own world. (And attempts to bring machines closer to these languages mostly did not succeed).

Objective-C provided these features with the slimmest of a sliver of an extension to a portable PDP-11 macro assembler.

Now that was mind-blowing!

And it goes beyond that: there actually was, at some point, Objective-Assembler. Objective-C was never intended to be "a language" like Java or Rust. The Objective part of Objective-C is a glue layer, an integration mechanism that can be added to any language. There was Objective-FORTRAN, Objective-Pascal etc. Helge Hess once put it almost perfectly: Objective-C is COM with language support. Or SOM. Or whatever interop mechanism they come up with again (Swift "library evolution", I am looking at you, can we have Objective-Swift?).

So it wasn't just mind-blowing, it also was, is, and remains incredibly useful.

So useful, in fact, that this slimmest sliver of an extension gradually replaced the portable PDP-11 macro assembler it was sitting on top of for most day-to-day use. So much so, that in the Apple developer ecosystem, the much larger C part started to be regarded as a completely separate language that most devs never dared touch.

Of course the fact that this is doable shouldn't be surprising, after all the Objective part is modeled after Smalltalk, and Smalltalk is a complete programming language. But Smalltalk requires a fairly large VM to run, typically coded in C or in Squeak's case, C plus BCPL-encoded-in-Smalltalk that gets automatically translated to C. Objective-C and Objective-Assembler showed that you don't actually need all that, just a tiny messaging function on top of bare machine is not just sufficient, it's also faster, integrates better and is easier to implement. Less is indeed more.

All that doesn't mean that Objective-C isn't an ad-hoc car crash of two languages with overlapping functionality and syntax, and the safety of C's memory model and Smalltalk's type system. That this disaster area works better in practice than most other languages tells you all you need to know about the state of PL design.

A more principled, if irreverent, exploration of the same approach can be found in Ian Piumarta's COLA (COmbined Lambda Architecture). He basically discovered the same principles, and came up with something that's even cooler, though at this point less practical.

My favorite bit (it's a tight field) is how he manages to build a message-dispatcher that is itself invoked by message-send. How does he resolve the infinite recursion inherent in the self-referential definition? By pre-populating a single cache.

Ian is also a really great speaker:

Alas this video of his Stanford EE380 talk is only 240p, so the text is illegible, but fortunately there are slides that you can follow along.

In Objective-S, the procedural/OO part is really based on just that sliver of an extension. The C part is removed (yes, a real "Objective-C without the C"), replaced by a few type declarations for indicating primitive types, special stores for raw memory access when needed and a generalization of message-sending that subsumes calling C functions.

Wednesday, January 3, 2024

DAPLs: Domain Agnostic Programming Languages

Every once in a while, you get an insight that hits you like a truck. Or maybe a ton of bricks. Or a truck carrying a ton of bricks. Developing Objective-S has delivered a bunch of these, but one of the biggest was that our General Purpose Programming Languages are nothing of the sort. They are Domain Specific Languages for the domain of algorithms. See also: ALGOL. To move forward, programming languages will have to support more than just this one architectural style.

Alas, communicating this insight has been...challenging. One method was branding Objective-S as "the first general purpose programming language". This did not always go over well.

Or
It looks interesting. But stuff like this:
> Objective-S is the first general purpose programming language
Those kind of statements annoy me to be honest. Is it really true? Or is it over-the-top marketing hype? For me – and I'm sure I'm not the only person who feels this way – it creates a negative first impression.
skissane on May 9, 2021 on: Objective-S: architecture-oriented language based ...

Of course, there is no such thing as bad publicity, but this had a bit too much of a lunatic-fringe vibe, no matter how correct the insight, and no matter how ill-fitting the moniker "general purpose language" really is for our call/return-oriented algorithm-DSLs.

As Richard Feynman once put it, "One of the miseries of life is that everyone names everything a litte bit wrong, and so it makes everything a little harder to understand in the world than it would be if it were named differently". Calling our algorithm-DSLs "general purpose" implies that we have solved the problem of generality, when we have not, and that the only real alternative is to be more specific, hence DSLs. But DSLs also don't really work that well, because the successful ones almost invariable grow non-domain-specific features, just in a haphazard way. Or they need to be combined to cover different fields, so we get language workbenches that allow us to define lots of little DSLs and combine them.

This all points to the fact that our problem is not being too general, but too specific. Our algorithm-DSLs just aren't very good at covering a lot of the problems programmers have to solve, though of course they are Turing-complete and can get us there, somehow.

Riffing off those ideas, and leaving aside the minefield of incorrect but entrenched terminology, I propose the term Domain Agnostic Programming Language. Because any sufficiently powerful DSL can be bent out of shape sufficiently for any purpose, just like our algorithm-DSLs can. They just aren't a good fit. And so Objective-S is not the first general purpose language, it is the first, and almost certainly the worst, DAPL. And hopefully its programming environment will be dapper.