![]() | |
"Thread safety" is but a piece of accidental complexity caused by mapping the theoretical concept of synchronous "concurrency" (which is not the same as asynchronous "parallelism") onto synchronous, sequential hardware, such as a single CPU, using shared memory between processes.
The thread safety issue can be wiped out by using processes that don't share memory. For example, nodes on an internet do not share memory and don't cause thread safety issues between one another. Software implementing a node can choose to continue to use a shared memory model internally, and, hence, will not fully benefit from the simplicity of eradicating thread safety. Internet nodes are asynchronously parallel, but software inside nodes that use memory-sharing concurrency based on the synchronous, sequential paradigm cannot be parallel and are only synchronously concurrent.
Multi-core, as I understand it, doesn't give full relief from thread safety issues.
Switching to a pure message-passing paradigm internally will cause evaporation of thread safety concerns. Using function calls only looks like message-passing, but is actually an impure form of message passing (I don't know of a name for this impure form ; functions block when calling other functions, hence, also pass control flow along with message data). Just about any modern programming language, especially those that conform to "calling conventions" fall into the category of being accidentally complexified.
I'll see if I can come up with a better explanation that de-conflates these issues. This will require some more thought and time...
That’s what Software Architecture is for. Trying to generalize the solution (as was done with thread safety) only bloatifies the result.
State isn't actually bad. Reality contains state. State within the FP paradigm is bad, though.
Programming languages based on the synchronous, sequential paradigm (i.e. most current PLs) make the use of state very clunky (global variables, if-then-else, blobs of state passed around as data, etc). That is a "tell" that this issue should be handled in a different notation. I kinda like Harel Statecharts, as previously mentioned.
Languages like Prolog, Datalog, Ceptre, Nova, and concatenative languages are different (non-FP) approaches to the issue of state. Ceptre is based on linear logic. There are many ways of doing this other than by just doing the same thing over and over and expecting different results.
Automagic state coherence is just an inefficient trick that architects should be allowed to choose to use when necessary, instead of having it hard-wired into hardware and programming languages.
aside: SIMD and SIMT are just other automagic tricks that are very optimized for a narrow range of use-cases (graphics, GPUs), but, are just albatrosses around the necks of other use-cases.
The strive for generalization makes us feel that the solution to every conceivable problem must be spoon fed to us. Software Architects should want access to specialization and LEGO-like parts and layers. That's not what we have at this moment. It's within reach, though. It's mostly just a mind-set problem.
On Jun 19, 2026, at 9:48 PM, Raoul Duke <rao...@gmail.com> wrote:
still doesn't fix the core issue of state coherence / consistency
--
You received this message because you are subscribed to the Google Groups "PiLuD" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pilud+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/pilud/CAJ7XQb6Kyxtw3jELtxXiWjGA%3D%3DDR9LM%2BfaeL4zWx5Hm0s%2BWvHg%40mail.gmail.com.
To view this discussion visit https://groups.google.com/d/msgid/pilud/6CD4E7E8-3A40-4583-A6FB-039C0727BBC8%40gmail.com.
Thanks. That is a good description...
State isn't simply memory or mutation; it is any dependency of the future on the past.
Issues such as coherence and race conditions can appear just as easily with message passing as they do with shared memory. For example, a shared-nothing actor in an actor model can still model a "mutable cell" in memory. You'd still have race conditions between reading and writing these cells.
Coherence is not needed most of the time. Premature coherence gives rise to inefficiency and overkill.
There is but only one race condition - when two events A and B arrive "simultaneously", if you can't tell in what order they arrived in, then it's a race condition. All of the other so-called race conditions are accidental complexities created by the use of an inappropriate substrate paradigm.
The patterns of interaction are more relevant than whether those interactions are implemented using threads, actors, or processes.
Agreed. Maybe I'm reading more into what you've written than what you intended, but ... I perceive that our current trend of borrowing from the "functional programming" paradigm (starting with something like C) and wanting to believe that "everything is a computation" is a death march or, at best, a way to exponentially increase accidental complexity. Our use of functions for programming languages is just a convenience. It's a spherical cow that ignores asynchronicity, time and ordering to make some things simpler, but, it cannot - by definition - deal with the totality of Reality.
I believe that we need ways to reason about state and ordering of events, regardless of how convenient the "everything is just a computation" paradigm is (only for a subset of problem domains, though). Reality is composed of state. We cannot address Reality without addressing state. I note that Nobel laureate Ilya Prigogene said the same thing about the functional approach to physics. In "Order Out of Chaos" he says that this approach has set physics back by 100 years.
aside: our current programming languages allow us to handle state but only in a clunky, low-level way - using global variables and if-then-else, or, bags of state passed around as parameters. Notation is important - language influences thought. Harel showed a notation (Statecharts) for expressing stateful control flow in a more convenient way some 40 years ago. Part of the problem, IMO, is the belief that we should try to use only one language at a time and try to glue everything into that language or invent workarounds to fit the problem into the underlying paradigm of the one language. Programming languages are just caveman IDEs for programming, devised in the early days of programming. If we, instead, had IDEs that allowed us to build solutions by composing snippets of code tuned for each sub-domain (instead of blobs of tangled, work-around-filled code written using General Purpose Languages) we might be able to drastically increase our development turnaround time. (aside to aside: the current belief that using multiple languages is difficult is based on the use of General Purpose Languages instead of more laser-focussed Special Purpose Languages. I know that using multiple languages is not that hard).
Further:
The Spherical Cows of Programming
The Wrong Spherical Cow - First Principles of Parts Based Programming
The Case For Composable Notations (1 / 5) - The Spherical Cow We Forgot We Were Riding
The Case For Composable Notations (2 / 5) - The Restrictions That Came With The Cow
The Case For Composable Notations (3 / 5) - State Isn’t The Enemy
The Case For Composable Notations (4 / 5) - Ease of Expression Is the Whole Point
The Case For Composable Notations (5 / 5) - UNIX Already Showed Us the Way
The Case For Composable Notations (6 / 5) - WIP - Notations in Progress
To view this discussion visit https://groups.google.com/d/msgid/pilud/CAAOQMSu46GQXDPCgjoTf0qTkdckmjuYej810%2B8kUpBUNe-K4eA%40mail.gmail.com.
On Jun 28, 2026, at 9:02 AM, Raoul Duke <rao...@gmail.com> wrote:
For me, I think if one does not present an actual calculus for managing state, anything else is handwaving and borderline delusional since we already know how everything else is a fail. Things like MVCC at least try to start off admitting the kernel of truth.
--
You received this message because you are subscribed to the Google Groups "PiLuD" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pilud+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/pilud/CAJ7XQb4LyBCKyh2_xNQaQiQDzak%3DrZH1zQa4m2-R3%2BxLZhVSQQ%40mail.gmail.com.
Coherence is not needed most of the time. Premature coherence gives rise to inefficiency and overkill.
Agreed. Maybe I'm reading more into what you've written than what you intended, but ... I perceive that our current trend of borrowing from the "functional programming" paradigm (starting with something like C) and wanting to believe that "everything is a computation" is a death march or, at best, a way to exponentially increase accidental complexity.
Our use of functions for programming languages is just a convenience. It's a spherical cow that ignores asynchronicity, time and ordering to make some things simpler, but, it cannot - by definition - deal with the totality of Reality.
Notation is important - language influences thought.
There is but only one race condition - when two events A and B arrive "simultaneously", if you can't tell in what order they arrived in, then it's a race condition. All of the other so-called race conditions are accidental complexities created by the use of an inappropriate substrate paradigm.
Some form of coherence is needed, but there are weaker and stronger forms of coherence.
"Coherence often means that different parts of a system maintain a consistent view."
My perception is that the prevalent view of coherence (e.g. cache coherence) is too fine-grained for use in distributed systems.
Software architects should design-in coherence only when needed, i.e. through protocols and explicit synchronization. My perception is that our hardware and software insists on providing cache coherence at the expense of efficiency.
But something like Yves Lafont's Interaction Calculus (~1990) offers a more explicit foundation for modeling interactive, parallel, distributed systems than
Thanks. I need to learn more about that.
pt
Convenience is not something to scoff at. Unless you want to 'program' via physics simulations.
...
But our PLs could support a more-flexible lower-bound on abstraction.
I believe that the biggest missing ingredient in our programming languages is the notion of "time" (ordering, sequencing). It can be manually expressed in our languages, but, that's not the same as using a notation that treats it as a first-class concept.
pt
Focusing on this assertion specifically. It seems biased or privileged to centralized computation. Events "arrived" where?
I'm not sure I understand this point. The idea of events arriving somewhere is biased by a decentralized perspective. I think that that bias towards centralization is something that we got away with in the 20th century but we must move towards a decentralized bias in the next century.
pt
An important race condition is that different observers may see the same event stream in different orders. ...
I agree.
This is mostly a problem for distributed systems. But modern CPUs operate at such a frequency that light is moving less than 10cm per clock cycle. Relativistic light cones are an issue even within a LAN.
The "C" in CPU means Centralized. We've utilized notations for programming centralized CPUs to the point of overkill.
pt
The simplest resolution is to insist events, e.g. messages, are processed by only one component.
That is indeed simple. But, from a decentralized perspective all you need to do is to ensure atomicity of event delivery to prevent interleaving of events in time. If one adopts an asynchronous event delivery method (fire-and-forget), then this kind of atomicity can be quite cheap for geographically close devices, e.g. inside a single computer vs. spread across continents.
... A numbering sequence can help there.
Another method is to use queues or mailboxes with tagged events. One input queue and one output queue per component. Events are tagged with their port ids and enqueued, in order of arrival and generation, on those queues. It's not as fine-grained as using sequence numbers, but, it opens the door to many interesting, new architectures composed of asynchronous components, such as might be found in electronic schematics, like Atari Pong, 1972 (I'm currently trying to convert that thinking into Parts Based Programming (PBP) software). I find that simply allowing Parts to have multiple inputs and multiple outputs and making Parts asynchronous leads to interesting ideas and architectures more quickly than thinking using overly-synchronous notations.
pt
"Coherence often means that different parts of a system maintain a consistent view."
My perception is that the prevalent view of coherence (e.g. cache coherence) is too fine-grained for use in distributed systems.
Software architects should design-in coherence only when needed
My perception is that our hardware and software insists on providing cache coherence at the expense of efficiency.