CALL Violates Structured Programming
Structured Programming introduced the notion of nesting control flow with constructs like if-then-else, while, etc.
Object-Oriented Programming popularized the notion of nesting data via inhertiance.
OOP and Structure Programming do not fully isolate control-flow. CALL / RETURN
is usually supported in hardware by a global variable (the Stack).
CALL / RETURN
violates the single-entry-single-exit edict of Structured Programming. Programmers can CALL subroutines directly and “break through” the boundaries of a properly structured
To enable software construction using components, we must fully isolate data and control-flow.
Threads for Isolation of Control Flow
Threads, common in desktop operating systems like Linux, MacOS and Windows, isolate control flow in a heavy-handed manner. Threads often employ full-preemption and hardware MMUs.
Full preemption has caused a great deal of accidental complexity, e.g. the Mars Rover disaster.
Fixes for known problems have been developed, but it is clear that full preemption inhibits reasoning about designs.
Pure Functions for Isolation of Control Flow
FP restricts programs by expunging mutability to achieve isolation.
These kinds of languages severely restrict the programming paradigm(s) that can be employed to solve practical problems.
Calculators - One Input One Output
FP makes it easy to treat computers as calculators.
FP assumes that all functions have one block of inputs and one block of outputs.
FP is not well-suited to solving problems using paradigms that exceed this simple model.
Exceptions
For example, exceptions are usually treated as edge-cases with second-class syntax and second-class semantics.
Javascript
Javascript was invented for creating distributed programs (aka web pages).
Javascript continues to use function-like syntax with the result that simple distributed operations need to be programmed as callbacks.
Referential Transparency
An ideal for component-based design is the ability to replace components with pin-compatible ones.
In hardware design, this was called pin compatibility.
In functional progamming languages, this is called referential transparency.
FP languages achieve referential transparency by restricting the language paradigm that can be used.
FP expunges mutability and mutable operations.
(Note that this is not the only way to achieve referential transparency. A different solution was developed in the electronics industry in the 1950’s).
Hidden Dependencies - Global Variables
A major factor in the complexity of computer systems is the hidden dependencies between modules and the hardware-supported used of a global Stack.
Earlier computers, e.g. the IBM 360, did not have a hardware-supported Stack (programmers had to simulate a Stack using the BALR instruction).
Hidden Dependencies - Synchrony vs. Asynchrony
Most languages use a sequential function paradigm.
This sequential model resists the natural paradigm for computing - asynchronous operation.
It should be noted that asynchrony is common in human experience
- the human body contains an autonomous nervous system which consists of some 500 independent units
- children around the age of 5 learn to use a hard, real-time notation
- businesses run in a top-down manner (aka Org Charts) and consist of many independent units.
Concurrency
— spaghetti
— The Stack
— Scalability
— Superposition