Now: A Concept Whose Time Has Come And Gone?

I recently came across the Flow Programming Language, which aims to “solve the multicore dilemma through ubiquitous, guaranteed-safe implicit parallelization”. However, rather than going down the route of Functional Programming, it aims to do so for imperative languages. This lead to an interesting claim:

The specific minimal way that an imperative programming language must be restricted to make programs written in that language precisely implicitly parallelizable is to make it impossible to read the current value of a variable.

In other words, “there is no such thing as the concept of ‘now’ in the program”. This lead to the following alternative options:

  1. Reading the only value that a variable will ever take i.e. immutability.
  2. Reading the value of a variable at a specific (local) timestamp.
  3. Reading the set of all values that a variable will ever take on i.e. pushing values into a collection.

What I find interesting about this is that the first two options are making time an explicit concept within the language: either a variable has a single value for all time, or else you must ask for the value at a specific point in time.

However, the Flow language is a long way from even an Alpha release, so I filed it under “intriguing but not going to impact me for a while”. But my interest was piqued, so I went searching for more information about models of time within current programming languages, and only really came up with one option: Clojure’s Epochal Time Model.

The linked video is essential viewing for a proper understanding, but for the purposes of this post there is a nice summary here. The key concepts are Identity (e.g. me), State (e.g. hungry), and functions that cause the state of the identity to transition to a new value (e.g. Eat muffin, resulting in me being satiated.). State is immutable, and Identity is a concept that ties together a sequence of these states.

Clojure has a number of ways of modelling identity: vars, refs, atoms and agents, depending on the exact semantics required for access to the underlying state (aside: it would be nice to see the equivalents in F#). However, what they all share is that there is just one underlying state i.e. they are still operating in the “now”.

Then I listened to the Relevance podcast episode with Michael Nygard. In it the host (Craig Andera) mentioned that “there is no such thing as ‘now’”. This was said in the context of a discussion around Datomic (a time-aware database of immutable facts) and distributed systems, where you can never be sure you have the most up-to-date information. Datomic has a very explicit time model, where each fact has an associated transaction, which in turn has both a relative and an absolute time value. This seems to be the piece that is missing from Clojure’s time model.

And finally I was struck by a real world example from my current project. Our application requests data from a 3rd party, but the default API assumes that the request is for the latest data. So the response depends on the time at which the request was sent. The horror, the horror.

However it would be unfair to pick on that particular API, because this style of programming is the default approach today.¬†Programming in the “now” implies an implicit dependency – time – and even though we agree that¬†implicit dependencies are bad, we are blind to this one. Not only have we all written APIs like the above, haven’t we all also written code like the following?

prev = curr;
curr = CalcNewValue(prev);

Or how about?

var timeSeries = new List<Foo>(); // index represents time order
for (var t = 0; t < 10; t++)

In both cases we are kludging together a representation of time using language features – variable names in the first example; list indexing in the second – because time is not a first class concept in the language.

We have known for a while that manual memory management is painful and error-prone, and many languages now provide garbage collection to relieve us of that burden. However, when it comes to time, we are still left to manage that for ourselves.

I think the sane default should be that all (immutable) values should be associated with a point in time, which might be local or global, absolute or relative, depending on nature of the problem. And our languages and/or libraries should provide support for this, rather than requiring us to hand-roll our own implementations every time.

Waiting for language-level support for this does not help in the short term, so we need libraries to help us out. In future posts I’ll explore some possible implementations using F#, as decent support for immutability is an essential prerequisite.