Programming languages and operating systems are just tools for developers. Non-programmer end-users don't need either. Whatever we do on development machines must simulate what end-users get. Shipping 50,000,000 LOC operating systems, that contain developer helpers like context-switching, to end-users is over-kill.
We are in the age of programming for internet. Anything "global" like a callstack or a global tuple space, doesn't easily scale from our development workflow up into production.
Closures and queues simulate the internet and distributed computers better than callstacks and other global data structures. UNIX had the right idea, but was burdened by heavy-weight processes and heavy-weight queues. We can do better now. We don't need to continue over-using outdated paradigms, like stacks, low-level cache coherency, everything-is-a-purer-the-better-function, etc.
Actors and Erlang start out life built upon a non-suitable paradigm - callstacks, central computers. I've never seen an implementation of Actors that wasn't hampered by starting out on the wrong foot. If it uses “processes”, then it’s in the weeds.
I am encouraged by the work of Jart (Justine Tunney) who built a modern Lisp in 436 bytes and a closure-based, functional language (BLC) in 383 bytes (the demos run on top of a bloated operating system, but are meant to fit in a boot sector and to run before the operating system is activated).
Programming languages based on the paradigm of functions cannot (easily) scale to today's distributed problem space. It can be done with things like callbacks, async, await, .then, etc., but, these ain’t uncomplicated.
Programming languages based on the paradigm of global tuple spaces cannot (easily) scale to today's distributed problem space.
In fact, one must be careful when using any paradigm implemented on top of the paradigm of functions. Without care, the paradigm of functions will leak into the solution and cause concurrency problems down the road.
The Kitchen Sink
An Arduino is just a stand-alone Actor. Multiple Arduinos are multiple stand-alone Actors.
We have been using the idea of developing for 1950s hardware, then shipping the whole development mess to end-users.
As we get more and more into distributed problems (internet, IoT, robotics, etc.) this programming model with fail, or, at least will fight against forward progress, like we saw with callback hell, and are seeing with increasingly complicated expressions of simple concepts - complications like async, await, .then, package managers, etc.
Multiple Actor-like behaviour can be faked out on a computer using multiple closures-with-queues-and-a-dispatcher. Can we do this? Yes. I am doing it with 0D1. I’m currently calling this part based programming. In fact, this approach provides the effect of “green threads” to even lowly languages, like Javascript. Any language that supports the creation of queues and the idea of first-class functions can do this.
Node-and-Arrow, Actors, et al
Many node-and-arrow implementations embed functional thinking into their designs, usually in a back-handed way. This means that the implementations violate the principles of pure data-flow seen in UNIX pipes.
Many node-and-arrow implementations force arrows to mean "data-flow AND control-flow".
Control flow micro-management must be carefully removed from arrows.
Furthermore, node-and-arrow notations tend to eschew a structured approach based on layering. They allow arrows to poke through the boundaries of nodes and they allow more than 7±2 nodes on a diagram.
In other words, many node-and-arrow implementations only look like they deal with asynchronous components, but, are actually synchronous at heart.
Clients and Servers Are Not Pure Functions
Clients and servers have long lifetimes.
They accept inputs spread out over time.
They produce outputs spread out over time.
They can even cause side-effects.
Furthermore, CPUs cause mutation and random access and deal with control flow over time.
The Functional Programming paradigm is obviously useful, but, since FP forbids the existences of core principles of CPUs, like mutation, and, FP elides time at a basic, syntactic level, one must conclude that FP isn’t the only useful paradigm for programming.
Clients and servers are not pure functions. Using pure functions to describe clients and servers just makes the task of expressing what clients and servers do, harder.
See Also
References: https://guitarvydas.github.io/2024/01/06/References.html
Blog: guitarvydas.github.io
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Gumroad: tarvydas.gumroad.com
Twitter: @paul_tarvydas
Substack: paultarvydas.substack.com