TL;DR
Computer Science isn’t about programming. Computer Science is about mapping computational thinking into the digital domain and discovering problems in an ad-hoc manner, then fixing the problems to make the mapping work on reprogrammable electronic machines.
L;R
Regarding the Future of Coding podcast of https://futureofcoding.org/episodes/073 entitled “Moving Beyond Syntax: Lessons from 20 Years of Blocks Programming in AgentSheets, by Alexander Repenning”. The discussion of computational-thinking at around 2:08:13 resonates deeply with me and puts into new words something that has been niggling at me for a while.
We have had the function-based paradigm foisted upon us as being the epitome of "programming" since the early days of computering by people who wished that the new, and, unfamiliar concepts of reprogramming could be couched in old-fashioned mathematical notation.
So-called "computer science" using only the function-based programming paradigm, is but one approach to programming. It is a way of using hardware to build hand-held calculators for computation, and, for transforming papyrus-based, instantaneous, functional-thinking into the digital domain. Computer Science is not an exploration of the capabilities of reprogrammable electronic machines, it’s an exploration of how to digitize computational thinking.
The Mother Of All Demos[1] succeeded because the creators were not bound only by the function-based paradigm, e.g. the mouse was not designed as a function, code was probably written in assembler using subroutines, not software functions, etc.
CPUs do not directly support functions. You have to add extra software - scaffolding like preemption, context switching, MMUs and swapping, etc. - to support the concept of functions. Even so-called low-level programming languages that are supposedly "close to the hardware" - like C - employ functions and, thus, add layers of extra concepts on top of the hardware.
After 50+ years of research, the mapping of paper-based, Gutenberg-press-affected functions and functional notation[2] into the digital domain, is still incomplete.
Software functions cause ad-hoc blocking and require extra bloatware as scaffolding to support the simulation of the functional paradigm. The bloatware manifests itself as operating systems and old-fashioned IDEs called programming languages.
Software functions are synchronous - by definition - hence, software functions can never be used to express asynchronous concurrency. By definition. The best that can be done with the function-based paradigm is to express synchronous concurrency (step-wise simultaneity) and to define assembler-like primitives at the edges of the paradigm - like thread libraries - that can be used to connect distributed nodes together in clumsy, primitive, bug-ridden ways. The hardware of 2024 consists of systems of multiple reprogrammable electronic machines, whereas the hardware of the 1950s1 consisted of single, very expensive reprogrammable electronic machines. Software of the 1950s addressed only hardware of the 1950s using IDEs called programming languages and progressively more complicated type checking. We use stale 1950s ideas to address our new kinds of hardware in 2024.
In my mind, coding is the act of writing textual software functions based on computational thinking, whereas programming is doing whatever it takes to control reprogrammable electronic machines. Reprogramming is one of the new interesting, albeit unfamiliar, concepts in the domain of reprogrammable electronic machines. Programming and reprogramming networks of reprogrammable electronic machines is another one of the new, interesting concepts in this domain. Imposing computational thinking and function-based ideas onto programming is but a tiny sliver of possible approaches.
Computational thinking overlaid onto reprogrammable electronic hardware is clearly a useful paradigm, but it is not the only paradigm for programming.
It appears to me that programmers conflate the concepts of programming and coding. I think that these are different concepts.
We see a difference in even the lowly Atari Pong game[3]. In 1972, Pong could be expressed on one (C-sized) sheet of paper using 0 functions. Today’s Pong, written in a synchronous programming language, occupies many sheets of paper and needs scaffolding amounting to something like 50,000,000 LOC.
Why do programmers write code? There is only one language that can be used to program CPU chips - assembler. All programming languages boil down to assembler (assuming that a CPU is used at all).
In the 1950s, most computers were stand-alone machines and it made sense to build IDEs based on so-called higher level languages that protected developers from making too many mistakes when producing assembler code.
Today, though, developers need to program collections of computers - networks of nodes on the internet, networks of nodes in robots, multiple nodes in cell-phone networks, many NPC nodes in game software, many intermittent participants in blockchain, networks of nodes in IoT, many nodes inside of LLMs, etc., etc. The basic problem space has shifted. Does it still make sense to use 1950s-style IDEs to develop software for such collections of nodes?
Tells
I see many “tells” that we should be programming reprogrammable electronic machines with new kinds of ideas and IDEs.
For example, the concept of callbacks, for programming asynchronous networks, essentially failed (due to assembler-like unstructuredness?) and was “improved” through the addition of more complexity to old-fashioned1950s-style IDEs - promises, futures, .then, etc., etc.
Another “tell” is simply the exponential rise in the memory footprint of production software. In the 1950s, programmers used words like bytes and kilobytes, whereas, today, programmers blithely think in terms of megabytes and terabytes. Certainly the size of data has increased - images are stored at higher resolutions - but, this does not need to imply that the size of code needs to increase. What causes this increase in code size? Non-programmers think of memory as cells in a calculator controlled by the M+ and Recall buttons. One cell of memory, or a stack of cells. Not millions of cells.
The fairly modern language “Sector Lisp”[4] has a footprint of less than 512 bytes. Why is any language larger than that? Sector Lisp relies on pure functional programming (FP). Pure FP dictates that mutation is forbidden. We shoved the concept of mutation into our 1950s-style programming languages. Is that the cause of the observed size bloat? FP forbids memory sharing. We shoved the concept of memory sharing into our 1950s-style programming languages, and, thus, into every app. Is that the cause of the observed size bloat?
I’ve heard hand-waving arguments about “essential complexity”. All problems are complex until someone researches them and explains them in a less-complicated manner. What, exactly, is the “complexity” that causes the observed size bloat? Why are we not attacking those specific issues of complexity?
Question Everything
Something smells bad. What is it?
Is it possible that our belief in digitized computational thinking and the attendant need for ever more complicated forms of type checking are the cause of the bad smell? Are programmers shipping products that still contain artefacts of type-checking and computational thinking, without optimizing all of that stuff away? Programmers need preemption-based operating systems to help them catch bugs and runaway programs. But, end-users don’t need such over-wrought operating systems - why aren’t operating systems optimized away during production engineering?
We prefer statically typed programming languages because we believe that dynamically typed programming languages need too much Q/A.
Yet, programmers still need to perform Q/A. Using statically typed programming languages, programmers continue to ship buggy products, as witnessed by their reliance on CD - Continuous Delivery - in their workflow. The attitude appears to be that products can be fixed in the field, later, hence, the products don’t need to be perfected first.
Programmers do ship stuff to the market more quickly, and, programmers do produce products that seem to be larger and more awe-inspiring, but, the four-9s attitude of the telecom days has disappeared2.
It seems that programmers’ workflows allow them to get stuff out the door faster than in the past, and, in greater quantity, but, in general the products don’t have a high level of reliability.
Did the shift from dynamic programming languages to static programming languages make things better? Did the shift from assembler to higher level languages make the final products better? Developers think “yes”. But, end-users still need to spend $$$s to buy sophisticated computing devices, pay tax for 50,000,000 LOC developer-oriented operating systems, and, are expected to pay for the privilege of doing unpaid Q/A (re-branded as “beta-testing”). Developers need preemption, but do end-users actually need preemption? Yes, only to protect buggy apps from other buggy apps - end-users wouldn’t need full-blown preemption if the apps they paid for were reliable - something like game cartridges would be enough.
Why do programmers accept warped programming languages that accommodate all of the rules of digitized computational thinking, instead of simply using better linters?
Is the current fad of A.I. using software LLMs an amazing feat of technological prowess, or, just good marketing? It is my belief that other disciplines were making advances in this kind of A.I. earlier, but, didn’t market it as well.
Is software something special? Or, is software just soft hardware?
The software of the Mars Pathfinder[5] crashed soon after the craft landed on Mars. After a few days of furious study, NASA found a way to send a software update to the Pathfinder that fixed the problem, but, could only send it when Mars and Earth were facing the right way. This story is touted as a success instead of as a failure. Why? The problem was in the operating system, i.e. in the extra software scaffolding needed to simulate functions and support the digital computational paradigm.
Bibliography
[1] The Mother Of All Demos from https://en.wikipedia.org/wiki/The_Mother_of_All_Demos
[2] The Story of the Vinculum from
[3] The original Pong video game had no code and was built using hardware circuitry. Here's the original schematics from Atari from https://www.reddit.com/r/EngineeringPorn/comments/ul49zt/the_original_pong_video_game_had_no_code_and_was/
[4] LISP with GC in 436 bytes from https://justine.lol/sectorlisp2/
[5] Mars pathfinder disaster from https://guitarvydas.github.io/2023/10/25/Mars-Pathfinder-Disaster.html
See Also
References: https://guitarvydas.github.io/2024/01/06/References.html
Blog: https://guitarvydas.github.io
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/Jjx62ypR
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Gumroad: https://tarvydas.gumroad.com
Twitter: @paul_tarvydas
When I use the year 1950, I am generalizing, and, not wanting to be specific. I mean “early computing”, but 1950 is better click-bait.
99.99% uptime. No single point of failure. When there was a power outage, the phones still worked. In fact, people would call their friends to ask if they were having a blackout, too, without even noticing that they were using technical devices in the process.