August 30, 2018
Let’s talk about self-aware systems. Nah. Let’s start with something simpler. What if we apply the systems engineering approach to the programming language design first?
Let’s start with a simple example. A single, pure function. Which aspects does it have?
Inputs, outputs, as seen from the nominal (domain, codomain) and structural (data representation) perspective
Input-to-output projection semantics (what the function computes). Again, while side effects are an interesting topic, let’s leave them out for now. I’ll cover them in the later posts.
Nominal and structural implementation
Nominal and structural cause. Simply, “how did we get here?”
What’s the proper name for this one? Origin? Or maybe intent?
(reminder for future posts) Of course, a function does not exist in a vacuum. At some point, we’ll also have to deal with lifecycle, execution, resource, time, concurrency and I/O semantics.
Surprisingly, all of these aspects are entirely optional! Each one can be left out altogether, handled implicitly, explicitly, or present as a fully-featured, first-class object, and a language will still be successful.
For example, assembly language isn’t concerned with nominal data or code representation at all, most languages have no macros (first-class code) or runtime reflection (first-class structural data representation), there was no real structural history before CVS and Git, no first-class types until D and Julia, and no first-class resources until Rust.
Also, I still don’t know of any language which has a first-class structural implementation (that is, where programmatic translations of your program to different, configurable targets is a common practice). TypeScript and Babel are moving in this direction, though.
Other problems, like formally-sound approaches to upgrades of code or data representation (database schemas), aren’t even thought of as being in the scope of programming language design. Which is strange, given the productivity gains previously achieved by making even one of these aspects fully explicit or first-class (like version control, or exceptions, or strict type systems)
Also, maybe it looks like it’s already highly advanced stuff, but sadly all the aspects we’re discussing so far are still low-level. We will also undoubtedly need things like Futures/Promises (or other ways to reason about time, as Moore’s law is over, and every system is a distributed system now), packages, etc., etc.
So, why not create a language that treats all of these aspects as first-class?
I’m not sure whether it’s still should be called a programming language, though. A system which also tracks requirements (nominal causes), test run results and bug reports (structural execution traces) and handles collaboration is much more than just a programming language. This is what the IDEs should’ve become, in my opinion.
What I like in this concept is that we can work with code in any language - both language definitions and programs are first-class, malleable objects. Thoughts, serialized in code.
What does all of this have in common with self-aware systems? Assuming all of the above feats work, it’s just one more step to being able to access and mutate the development environment itself (Emacs, anyone?).
But can we handle all these aspects simultaneously without our head exploding? We’ll discuss this in the next posts.