The Case for Composable Notations (4 of 5) Ease of Expression Is the Whole Point
2026-03-30
TL;DR
“You can express it in FP” is not good enough. If expressibility were sufficient, we’d still be programming in transistors. Notation shapes what gets built, what gets attempted, and what gets imagined.
L;R
There is a standard defence of any dominant notation when its limitations are raised: yes, but you can express that in it. You can express concurrency in a functional language. You can express state machines in a functional language. You can express asynchronous behaviour in a functional language. It takes more work, but it can be done.
This defence misses the point entirely.
The transistor argument.
We do not program in transistors. We could — every computation that runs on modern hardware is, at the lowest level, a pattern of transistors switching states. The transistor is expressive enough, in principle, to encode any program we have ever written or will ever write.
We do not program in transistors because the distance between transistors and human problems is too large. The notation does not fit the problem. Bridging that distance costs more than it is worth when better notations exist.
We do not describe programs in terms of molecules either, or atoms, or semiconductor physics. Each of those notations is, in principle, expressive enough. None of them are useful for programming, because usefulness is not about expressive sufficiency. It is about ease of expression.
This is why programming languages were invented. Not because transistors couldn’t express the computation, but because transistors made the computation too hard to express, reason about, modify, and communicate to other programmers. The notation mattered.
The same argument applies above the level of transistors. If a notation makes a class of problems hard to express, that is not a minor inconvenience to be overcome by sufficiently skilled programmers. It is a signal that the notation does not fit the problem domain.
What hard expression costs.
When a notation fights the problem, the cost is not just programmer time — though that cost is real and large. The cost is also in what does not get built.
A notation that makes concurrent systems hard to express produces fewer well-designed concurrent systems. Not because programmers are incapable, but because the overhead of expressing concurrency clearly in an ill-fitting notation consumes the budget that would have gone into design. The workaround ships. The design doesn’t.
A notation that makes state transitions hard to express produces programs where state transitions are implicit, scattered, and invisible. Not because programmers don’t understand state machines, but because the notation gives them no clean place to put one. The switch statement inside the loop ships instead.
A notation that makes multiple output channels awkward produces programs that smuggle outputs through exceptions and side channels. Not because programmers don’t know better, but because the notation makes “better” expensive.
The notation shapes the solution space. Not by preventing solutions, but by making some solutions cheap and others costly. Programmers, like water, take the path of least resistance. The notation defines which path that is.
Decades of baubles.
We have spent decades adding to the functional notation rather than supplementing it with alternatives. Monads for managing effects. Continuations for managing control flow. Async/await for managing the synchrony mismatch. Effect systems for managing side effects. Evaluation order rules for managing the cases where order matters.
Each addition makes the notation more capable of expressing something it was not originally designed to express. Each addition also makes the notation more complex, more demanding to learn, and further from the original idea that gave it its elegance.
The result is that the sweet spot of FP — the class of problems it expresses cleanly and cheaply — has not grown. The notation has grown around it. New programmers must now learn not just functional thinking but the accumulated stack of workarounds that make functional thinking usable outside its sweet spot. The beginner’s path into the notation runs directly through the complexity that the workarounds created.
This is not progress. This is a notation being stretched past its natural boundary because the alternative — acknowledging that different problems need different notations — has been treated as defeat.
Ease of expression is an engineering requirement.
In engineering, the right tool for the job is not a style preference. Using the wrong tool produces weaker results, at greater cost, with more risk of failure. A notation is a tool. A notation that does not fit the problem is the wrong tool.
The solution is not to make the wrong tool more elaborate. The solution is to have more tools and to know when to switch.
This is not a radical idea. Hardware designers use it routinely. A circuit schematic, a timing diagram, a state machine diagram, a truth table — these are different notations for different aspects of the same system. No hardware designer would insist on expressing everything in a single notation. The problem domain is too varied. Different aspects of the system have different natural notations.
Software has largely insisted on the opposite. One language, or a small family of languages sharing the same fundamental assumptions, for every problem. The notation is the craft. Questioning the notation is questioning the identity of the field.
That needs to change.
What ease of expression actually requires.
It requires that when we find a useful notation — function-based thinking, relational thinking, state-machine thinking, diagram-based thinking — we stop trying to make that notation do everything. We stop enbaubling it. We ask instead: what is this notation’s sweet spot, and how do we connect it to other notations for the parts of the problem it doesn’t fit?
The question is not “can this notation express the problem?” The question is “does this notation make the problem easy to express, easy to reason about, easy to modify, and easy to communicate?”
If the answer is no, the notation is the wrong tool. We are allowed to use a different one.
Next: UNIX Already Showed Us the Way.
See Also
Email: ptcomputingsimplicity@gmail.com
Substack: paultarvydas.substack.com
Videos: https://www.youtube.com/@programmingsimplicity2980
Discord: https://discord.gg/65YZUh6Jpq
Leanpub: [WIP] https://leanpub.com/u/paul-tarvydas
Twitter: @paul_tarvydas
Bluesky: @paultarvydas.bsky.social
Mastodon: @paultarvydas
(earlier) Blog: guitarvydas.github.io
References: https://guitarvydas.github.io/2024/01/06/References.html

