This is a dangerous way to think about it. State and time are different things, and if you think of them as the same, then your mental model glosses over some parts of reality that will become important as your software grows more complex.
State is inherently dangerous BECAUSE a program runs TEMPORALLY. As the number of state changes increases, the dangers of an unwanted state increase (particularly insidious are the state combinations you thought weren't even possible). This is why functional programmers favor immutability and idempotent functions.
Also: Just because the EXTERNAL observability of state hasn't changed is no reason to assume that no state changes have occurred. Hidden state changes are the most dangerous of all.
Stuff like Haskell I thought has the most of these kind of hidden state changes affecting space and time (e.g. a small code change throws off the magic optimizer and now it uses way more memory to try and efficiently support that immutability or takes exponentially more time).
Guys. State and change are not literally Hitler. Changes to state are what computers are made for. You will not write bug free programs. Haskell demonstrably does not reduce bugs over and above languages that allow direct state changes.
Instead of fostering an environment of being afraid of your data. Embrace it. Write the code that needs to be written. Accept that bugs will happen (before you slippery slope this, I am not saying to write bugs for the sake of it, or to use state in unintended ways).
You do not need to be afraid of your state. Join us on the light side.
State is dangerous - it's an entropy multiplier, so keep it within reason and for gods sake don't ignore it or pretend it doesn't exist.
We like to think that we have it all under control, but the time dimension multiplies everything, and has a tendency to ratchet them until suddenly you find that you actually don't have it under control anymore.
The less state you have, the less your brain gets turned into a pretzel trying to keep track of it all over the time dimension.
If you care very much about not ever ending up in a bad state (which it seems that you do). Then just functional programming with immutable state is not going to cut it. In this realm you should look into methods of formal verification to prove that your code does what you want it to do.
That being said, functional verification is a huge time sink and is really only economical if it's very important for the code to always be correct. That is, people die if your software has a bug. A few examples would be pacemakers, aircraft autopilots or your car brakes.
If your not working one of these domains then maybe immutable and pure functional code can save you a few bugs? I have not read any peer reviewed study that shows this is the case. But if you have any such paper i would be happy to read it.
Modern web would best be described as a fustercluck. Web tech still hasn't caught up to most of the lessons learned in the 70s 80s and 90s. Watching web GUI technologies evolve over the past 20 years was like watching bad 70s reruns, with all the cringe and facepalm.
We have enough to make a discipline out of the field, but every 20 years or so the next generation of fresh recruits brings all their bad habits in with them and then round and round we go again with the new (and horribly broken) technologies that didn't learn from the last time we did the same things and made the same mistakes in a similar way.
You absolutely can control how much state you need (down to a minima, of course). The issue is not with the minimum state necessary - it's with the cowboy mentalities that lead to excessive state (and even worse - excessively complicated state interactions).
For the room, yes, state and time happen to be the same thing.
However for a lot of systems thats not the case. Worrying about hidden state is the enemy of joy.
Sure, if you are doing shared things, or exposing the internals of something to the world, then yes, you need to be paranoid. But, marshalling things so that state is in a known and guarded place is a much better way to think about things.
State is basically the computer science version of an egg drop. There are many ways to make it work, some more complex than others. but worrying about sudden cross winds[0] isn't the way to make sure your egg doesn't shatter when it hits the floor.
[0] unless your arena has active cross winds of substance.
I think this is a useful way to model a simulation. Probably a good way to reason about bugs and how a program works.
However, I question if you want to try and embrace this on anything that takes on user input. It would be one thing if we had temporal logic based programming models. But I don't know if any program that does.
State changes that are internal to a function and not visible are sometimes called "benign effects" in functional programming. A function can be considered "pure" if it has only benign effects, which is a relaxation on the stricter requirement that a pure function have no (side) effects at all.
I'd argue that the way we define "state" as being "a set of things that matter to us". In the context of the article, if we define state as being a "state vector of (hours, minutes, seconds)" we explicitly exclude everything but these three value (miliseconds, date, etc). The two pictures with the hands pointing to the same umber then by definition are the same. We can even consider them as being the same "every 24 hour".
The distinction between single threaded or multi threaded is moot; the world is in perpetual mutation anyway; even is two lines of code are being executed at exactly the same time in a multithreaded fashion, one is executed on CPU A and one on CPU B so their "environment" is different and there will never be two lines of code that are executed in exactly the same environment - regardless of what tools and techniques you use to try and enforce reproducibility.
What matters is to explicitly define what you consider as having an impact (which you add in the "state") and what you don't (which you leave out).
It might be better to say "changes in state are time".
This is a deeper understanding of what time is than the common one we have... but... since "the common one we have" is the result of living in a universe that is absolutely constantly pounding state changes into us every Planck-time of our lives, and I don't know about you but I'm not building anything that I expect to exist in some sort of ontologically different state, you can do rather a lot of work with the "intuitive" concept of time. Even complicated server communications which are fast enough that the fact that relativity bans "simultaneous" becomes relevant can be understood just fine in an intuitive framework.
I do find it helpful to conceive of time as "state changes occurring" for a particular case, though, which is multithreaded programming. It is helpful to conceive of threads as "perceiving" time not as ticks on a clock, but changes in the state (which can be to a first approximation be 'lines of code executed'). From this point of view, threads do not experience time as a clock ticking onward, but as "a particular value that exists but only when they look". That is to say, if a thread "consults the clock" and determines that it is noon on Jan 1st, it can be helpful as a programmer to understand that that does not particularly mean that three lines later, it will be noon on Jan 1st. Arbitrary amounts of universe-time can progress between any two lines of code. Threads really relate to each other not across universe-clock time, but by what observable effects other threads cause on them, and only on what observable effects other threads have on them. In principle, two threads that cause no effects visible to the other are essentially running in different universes. This is a place that a mathematical mindset can really help.
But, again, this is just a sort of helpful thing for relatively advanced mental modeling, but you can get a long way just based on assuming a monotonic universe-clock.
This is why I assert, with some vigor but without much persistence (since it's obviously a massively uphill battle), that a clock-simulating library really should not be based on assuming threads will witness a monotonic universe clock, and a clock-simulating library ought to make it possible to test that a task nominally scheduled to come after some other task actually runs to completion before the first task even starts, because that can happen in the real world. In an imperative language, you can assume that one statement within a thread will follow another, and that the external threads you can see are also operating in that order, but the slip between those "ticks" can be arbitrarily large.
If you go on beyond this to "changes in [the part of] state [in this frame] are time", then your specs don't need to make allowances for stuttering (à la Lamport).
Actually, a state is when a measurable attribute of an object remains unchanged for a period of time. So saying state = time completely misses what a state is.
This is a better explanation, but can't the state be measured at any time, unchanged or not? The measurable attribute could always be in flux, for example.
Yes, basically as long as you keep measuring the object with a function (like length or weight etc) and the result of the measurement does not change, the state has not changed. When the result changes, its a new state.
Anyone who has worked on secure consensus has had the same thought. You can't derive time from pure math. You must observe some state change.
It's a useful concept, but strictly speaking it's not true. If this universe was completely devoid of matter, time would still pass. "If a tree falls in the woods and nobody is around to hear it, does it make a sound?"
Hmm, I would not say that a change in state = time, but that a state changes at some point in time where the state is current for the period of time (start to end) in which some measurable attribute of an object does not change. The standard for measuring time is based on planetary movement etc, so its really all about observing change as it happens, and the sequence of those changes.
If the universe was devoid of matter, it would mean there would be no us. And since time is a human concept, that concept would not exist :)
For anyone who finds this sort of discussion interesting, I highly recommend reading Chapter 3 of The Structure and Interpretation of Computer Programs. There is quite a bit of philosophical musing about the connection between time and state. For example:
> The basic phenomenon here is that synchronizing different processes, establishing shared state, or imposing an order on events requires communication among the processes. In essence, any notion of time in concurrency control must be intimately tied to communication. It is intriguing that a similar connection between time and communication also arises in the Theory of Relativity, where the speed of light (the fastest signal that can be used to synchronize events) is a fundamental constant relating time and space. The complexities we encounter in dealing with time and state in our computational models may in fact mirror a fundamental complexity of the physical universe.
Thanks for sharing that. Einstein and Minkowski knew perfectly well that space and time are inseparable over 100 years ago.
>Not sure what religion has to do with it.
>absolute time is not falsifiable…you have to believe in it.
Either time is a necessary condition for experience, or it’s a measurable object of experience. It can’t be both. You can’t have time in time. Which one do you believe in?
Are you saying: Lets say a Theory of Everything is found, it explains Relativity, and Quantum Mechanics, Gravity, . Everything is tied together. And, this theory does not have Time. Time is just a side effect we can measure. But, at that point, you would still need some 'belief'? Because it is so far beyond our ability to perceive it maybe?
Or, another way. Even a Theory of Everything, at it's root is just Math, it isn't 'what the universe actually is'. So we'd still need belief?
I realized this around 2016 while working in PHP/Laravel and realizing that mutation=state=time.
I use higher-order methods like map/reduce/filter now, storing temporary results in variables when needed (although PHP's lack of const variables is a travesty). PHP's functional model of receiving data, transmuting it with the help of copy-on-write arrays, and returning it with a possible side effect stored in a database, all in an independent process, is one of the best around IMHO. It's too bad that legacy mistakes/features in the language and performance inefficiencies in operating system multiprocessing implementations (Windows, cough) obfuscate how powerful this model is.
Most/all of the complexity in debugging comes from mutation and side effects. Unfortunately nearly every language gets this wrong. Python has a huge emphasis on mutating variables rather than returning values that can be piped to the next function. Rust goes to great lengths with its borrow checker to allow mutation when copy-on-write would negate most of the need for that. I'd like to see a language and even an operating system that piped data around rather than mutating it in place, with an accepted cost of taking about twice as much memory to accomplish it. Then code could be mapped directly to spreadsheet form, and code execution could be mapped to diffs between state transitions to provide rewind functionality and debugging for free.
I would love to work on a paradigm like this if I had any spare money and time at all to do it. I've waited since the 90s for what I consider basic features, but sadly almost no language got this stuff right in the time since. Which leaves me with the unfortunate impression that probably 90% of the work we do in programming is a waste of time. Imagine if that wasted effort had gone towards solving foundational problems in programming for the benefit of all, instead of internet lottery winners just rolling their profits into their next venture.
Are you proposing functional programming? There's plenty of examples of languages going that route (including languages with varying levels of compromise on 'pure' functionality for performance).
> code execution could be mapped to diffs between state transitions to provide rewind functionality and debugging for free.
Some of what you're saying reminds me of the JS library Immer. Using JS proxies (which can intercept and detect arbitrary object mutations), it allows you to produce a new state by mutating a "draft" copy of the current state.
The produceWithPatches function provides you with arrays of patches and inverse patches that are essentially diffs between the old state and the new state. You can then apply these patches and inverse patches (using Immer's applyPatches function) to rewind the state backwards and forwards. Elm was one of the first languages (on the frontend at least) to pioneer this concept of "time travel debugging", which was then popularized by the Redux DevTools web extension.
Completely disagree with the title. A system - especially software - can return to the same state at a later time. It makes no sense to conflate the two. It's telling that the author deliberately starts with a clock as an example - something whose state is supposed to reflect time.
The main point seems to be one about hidden state or unobservable internal state, and I'm all in favor of having that. One of my preferred ways to make software subsystems (particularly in embedded devices) is to use a state machine. To the outside software there may be only a handful of visible states - NOT_READY, READY, MODE1, MODE2, MODE3, FAULTED. But internally there may be any number of intermediate states - several startup states hidden behind NOT_READY, several transitional steps in mode changes, etc. When switching modes I prefer to report the old mode until a transition is complete and then show the new mode as the current state to the outside world. IMHO you don't want to report "in transition" or anything like that, the outside may need to tolerate some time going by before getting what it wants, but it's not needed to know what's happening internally. You either get there or fault. The simplification from what's happening to what's reported is important to reduce the spread of complexity.
State is a value in a system that may change over time.
I would like to add “… that can be accessed from more than one scope”, but that doesn’t quite match common usage of the term so might just cause confusion.
The distinction is useful, though, because values that change over time but only exist in one scope are easy to reason about and handle correctly, while ones shared across scopes can cause no end of problems if not well organized. Maybe we can use terms something like “trivial state” and “significant state”.
(And, yes, we’d also need to define “scope”. I think the intuitive/common meaning is enough to get the point across though.)
from having built a bunch of tiny indie games in a prior life (in Flash :P), time = state, and time = world
and depending on what games we're building, either we record actions as state changes (eg chess / turn based games: if no moves are made, time didn't elapse), or "real-time" games (eg chess w/ a world state like a clock)
Are they saying I just need to let the universe reach the desired state I want it in as a totally deterministic universe,then merely record that timestamp?
To read my data, I wait for the gnab gib to restart the phone universe?
I know it's about programming, but I have a thought experiment I think about occasionally. Imagine a universe with one point particle. There's no time or space. Add another particle. The particles can either be separate or at the same point. So in some sense there is time, since we can go between separate and together states. There still isn't space, I think? Is this a philosophical subject I can read about?
Only replying because playing same thought in head. Once two points relation exists. Simplest form distance. Either may be considered centre. Infinite points exist along that relation. And more can be imagined. The set of all points having the same distance from A as the distance from A to B etc.
Why would there be no time and space just because there's only a single one point particle? The empty space around the particle would still exist. Why would there be no time? Time could still be moving forward even if the universe consisted only of a single particle.
Edit: Unless you're saying that the coordinates system is such that the universe literally consists only of that single particle and has no time dimension, in which case your thought experiment is inadequately specified because you need to say how the expansion of the universe happens such there is something for another particle to come into existance in.
45 comments
[ 3.4 ms ] story [ 104 ms ] threadState is inherently dangerous BECAUSE a program runs TEMPORALLY. As the number of state changes increases, the dangers of an unwanted state increase (particularly insidious are the state combinations you thought weren't even possible). This is why functional programmers favor immutability and idempotent functions.
Also: Just because the EXTERNAL observability of state hasn't changed is no reason to assume that no state changes have occurred. Hidden state changes are the most dangerous of all.
Guys. State and change are not literally Hitler. Changes to state are what computers are made for. You will not write bug free programs. Haskell demonstrably does not reduce bugs over and above languages that allow direct state changes.
Instead of fostering an environment of being afraid of your data. Embrace it. Write the code that needs to be written. Accept that bugs will happen (before you slippery slope this, I am not saying to write bugs for the sake of it, or to use state in unintended ways).
You do not need to be afraid of your state. Join us on the light side.
State is dangerous - it's an entropy multiplier, so keep it within reason and for gods sake don't ignore it or pretend it doesn't exist.
We like to think that we have it all under control, but the time dimension multiplies everything, and has a tendency to ratchet them until suddenly you find that you actually don't have it under control anymore.
The less state you have, the less your brain gets turned into a pretzel trying to keep track of it all over the time dimension.
That being said, functional verification is a huge time sink and is really only economical if it's very important for the code to always be correct. That is, people die if your software has a bug. A few examples would be pacemakers, aircraft autopilots or your car brakes.
If your not working one of these domains then maybe immutable and pure functional code can save you a few bugs? I have not read any peer reviewed study that shows this is the case. But if you have any such paper i would be happy to read it.
A complex application will probably have more. An easy application will probably have less.
If the modern web has taught us anything at all, it should be that trying to fit small pieces of state together like a puzzle ain’t it.
We have enough to make a discipline out of the field, but every 20 years or so the next generation of fresh recruits brings all their bad habits in with them and then round and round we go again with the new (and horribly broken) technologies that didn't learn from the last time we did the same things and made the same mistakes in a similar way.
You absolutely can control how much state you need (down to a minima, of course). The issue is not with the minimum state necessary - it's with the cowboy mentalities that lead to excessive state (and even worse - excessively complicated state interactions).
The map is not the territory.
However for a lot of systems thats not the case. Worrying about hidden state is the enemy of joy.
Sure, if you are doing shared things, or exposing the internals of something to the world, then yes, you need to be paranoid. But, marshalling things so that state is in a known and guarded place is a much better way to think about things.
State is basically the computer science version of an egg drop. There are many ways to make it work, some more complex than others. but worrying about sudden cross winds[0] isn't the way to make sure your egg doesn't shatter when it hits the floor.
[0] unless your arena has active cross winds of substance.
However, I question if you want to try and embrace this on anything that takes on user input. It would be one thing if we had temporal logic based programming models. But I don't know if any program that does.
The distinction between single threaded or multi threaded is moot; the world is in perpetual mutation anyway; even is two lines of code are being executed at exactly the same time in a multithreaded fashion, one is executed on CPU A and one on CPU B so their "environment" is different and there will never be two lines of code that are executed in exactly the same environment - regardless of what tools and techniques you use to try and enforce reproducibility.
What matters is to explicitly define what you consider as having an impact (which you add in the "state") and what you don't (which you leave out).
This is a deeper understanding of what time is than the common one we have... but... since "the common one we have" is the result of living in a universe that is absolutely constantly pounding state changes into us every Planck-time of our lives, and I don't know about you but I'm not building anything that I expect to exist in some sort of ontologically different state, you can do rather a lot of work with the "intuitive" concept of time. Even complicated server communications which are fast enough that the fact that relativity bans "simultaneous" becomes relevant can be understood just fine in an intuitive framework.
I do find it helpful to conceive of time as "state changes occurring" for a particular case, though, which is multithreaded programming. It is helpful to conceive of threads as "perceiving" time not as ticks on a clock, but changes in the state (which can be to a first approximation be 'lines of code executed'). From this point of view, threads do not experience time as a clock ticking onward, but as "a particular value that exists but only when they look". That is to say, if a thread "consults the clock" and determines that it is noon on Jan 1st, it can be helpful as a programmer to understand that that does not particularly mean that three lines later, it will be noon on Jan 1st. Arbitrary amounts of universe-time can progress between any two lines of code. Threads really relate to each other not across universe-clock time, but by what observable effects other threads cause on them, and only on what observable effects other threads have on them. In principle, two threads that cause no effects visible to the other are essentially running in different universes. This is a place that a mathematical mindset can really help.
But, again, this is just a sort of helpful thing for relatively advanced mental modeling, but you can get a long way just based on assuming a monotonic universe-clock.
This is why I assert, with some vigor but without much persistence (since it's obviously a massively uphill battle), that a clock-simulating library really should not be based on assuming threads will witness a monotonic universe clock, and a clock-simulating library ought to make it possible to test that a task nominally scheduled to come after some other task actually runs to completion before the first task even starts, because that can happen in the real world. In an imperative language, you can assume that one statement within a thread will follow another, and that the external threads you can see are also operating in that order, but the slip between those "ticks" can be arbitrarily large.
If you go on beyond this to "changes in [the part of] state [in this frame] are time", then your specs don't need to make allowances for stuttering (à la Lamport).
Anyone who has worked on secure consensus has had the same thought. You can't derive time from pure math. You must observe some state change.
It's a useful concept, but strictly speaking it's not true. If this universe was completely devoid of matter, time would still pass. "If a tree falls in the woods and nobody is around to hear it, does it make a sound?"
If the universe was devoid of matter, it would mean there would be no us. And since time is a human concept, that concept would not exist :)
> The basic phenomenon here is that synchronizing different processes, establishing shared state, or imposing an order on events requires communication among the processes. In essence, any notion of time in concurrency control must be intimately tied to communication. It is intriguing that a similar connection between time and communication also arises in the Theory of Relativity, where the speed of light (the fastest signal that can be used to synchronize events) is a fundamental constant relating time and space. The complexities we encounter in dealing with time and state in our computational models may in fact mirror a fundamental complexity of the physical universe.
https://mitp-content-server.mit.edu/books/content/sectbyfn/b...
Time does not exist at all, the Universe is itself just changing from one State to the Next State. There is no Time Dimension at all.
Some theologians believe time exists also in Heaven. If that’s so it can’t be like any time we know about.
It is some latest physics theories that there isn't a 4th Time dimension, and the universe is moving from one state to the next.
And this programming example was a good illustration.
This is from 2011 https://phys.org/news/2011-04-scientists-spacetime-dimension...
Not sure what religion has to do with it.
Either time is a necessary condition for experience, or it’s a measurable object of experience. It can’t be both. You can’t have time in time. Which one do you believe in?
Or, another way. Even a Theory of Everything, at it's root is just Math, it isn't 'what the universe actually is'. So we'd still need belief?
I use higher-order methods like map/reduce/filter now, storing temporary results in variables when needed (although PHP's lack of const variables is a travesty). PHP's functional model of receiving data, transmuting it with the help of copy-on-write arrays, and returning it with a possible side effect stored in a database, all in an independent process, is one of the best around IMHO. It's too bad that legacy mistakes/features in the language and performance inefficiencies in operating system multiprocessing implementations (Windows, cough) obfuscate how powerful this model is.
Most/all of the complexity in debugging comes from mutation and side effects. Unfortunately nearly every language gets this wrong. Python has a huge emphasis on mutating variables rather than returning values that can be piped to the next function. Rust goes to great lengths with its borrow checker to allow mutation when copy-on-write would negate most of the need for that. I'd like to see a language and even an operating system that piped data around rather than mutating it in place, with an accepted cost of taking about twice as much memory to accomplish it. Then code could be mapped directly to spreadsheet form, and code execution could be mapped to diffs between state transitions to provide rewind functionality and debugging for free.
I would love to work on a paradigm like this if I had any spare money and time at all to do it. I've waited since the 90s for what I consider basic features, but sadly almost no language got this stuff right in the time since. Which leaves me with the unfortunate impression that probably 90% of the work we do in programming is a waste of time. Imagine if that wasted effort had gone towards solving foundational problems in programming for the benefit of all, instead of internet lottery winners just rolling their profits into their next venture.
Some of what you're saying reminds me of the JS library Immer. Using JS proxies (which can intercept and detect arbitrary object mutations), it allows you to produce a new state by mutating a "draft" copy of the current state.
The produceWithPatches function provides you with arrays of patches and inverse patches that are essentially diffs between the old state and the new state. You can then apply these patches and inverse patches (using Immer's applyPatches function) to rewind the state backwards and forwards. Elm was one of the first languages (on the frontend at least) to pioneer this concept of "time travel debugging", which was then popularized by the Redux DevTools web extension.
The main point seems to be one about hidden state or unobservable internal state, and I'm all in favor of having that. One of my preferred ways to make software subsystems (particularly in embedded devices) is to use a state machine. To the outside software there may be only a handful of visible states - NOT_READY, READY, MODE1, MODE2, MODE3, FAULTED. But internally there may be any number of intermediate states - several startup states hidden behind NOT_READY, several transitional steps in mode changes, etc. When switching modes I prefer to report the old mode until a transition is complete and then show the new mode as the current state to the outside world. IMHO you don't want to report "in transition" or anything like that, the outside may need to tolerate some time going by before getting what it wants, but it's not needed to know what's happening internally. You either get there or fault. The simplification from what's happening to what's reported is important to reduce the spread of complexity.
State is a value in a system that may change over time.
I would like to add “… that can be accessed from more than one scope”, but that doesn’t quite match common usage of the term so might just cause confusion.
The distinction is useful, though, because values that change over time but only exist in one scope are easy to reason about and handle correctly, while ones shared across scopes can cause no end of problems if not well organized. Maybe we can use terms something like “trivial state” and “significant state”.
(And, yes, we’d also need to define “scope”. I think the intuitive/common meaning is enough to get the point across though.)
and depending on what games we're building, either we record actions as state changes (eg chess / turn based games: if no moves are made, time didn't elapse), or "real-time" games (eg chess w/ a world state like a clock)
To read my data, I wait for the gnab gib to restart the phone universe?
Edit: Unless you're saying that the coordinates system is such that the universe literally consists only of that single particle and has no time dimension, in which case your thought experiment is inadequately specified because you need to say how the expansion of the universe happens such there is something for another particle to come into existance in.
A state is an identifier for a sequence of "atomically" changing values.
By "atomically" I mean before/after an event is handled end-to-end.