I ended up with virtually expanding the computer memory in time so that each memory access now requires two arguments: (1) the address of the memory cell and (2) the time at which the cell should be read or written.
It has always bugged me that in today's computer programs time is represented by time-stamps (for example, the 'validSince' and 'validUntil' time-stamps included in many data models).
Personally I find it cumbersome (and error prone) to always sub-select on these time-stamps in order to find the currently valid data set.
That's why I began to look for alternative solutions.
Micro-Versioning is a memory management technique that tracks changes on a very detailed (microscopic) level. This is somewhat comparable to a spreadsheet that supports change tracking.
Micro-versioning provides pretty much the same change tracking functionality — only at a much lower level, i.e. spreadsheet cells become memory cells and the version-select-menu becomes a time-operation.
Time-operations are CPU instructions that swap the times for which the memory should be read or written. A time-operator is the programming language counterpart of a time-operation, i.e. a time-operator triggers a time-operations.
For example, the following code snippet shows how the time-operator "AT" can be used to read the memory as it looked on 1 June 2018.
SELECT Article.(name, price) AT '1 Jun 2018';
> name price
------------------
pencil 0.99 USD
paper 4.99 USD
Technical details (for those of you that are interested): The execution stack includes a variable called $NOW which stores the time that is used for memory read/write operations. A time-operator can manipulate this variable. In the concret case of the above example the following happens: (1) the time-operator internally caches the current value from $NOW and then sets $NOW to '1 June 2018', then (2) the names and prices of all articles are read from memory (using the read-time '1 June 2018' now), and after that (3) the time-operator sets the $NOW variable back to the cached value so that subsequent memory reads/writes use the original value again.
With time-operators the handling of time becomes very intuitve.
For example, the following code snippet calculates the pencil price change between today and the beginning and June 2018.
SELECT pencil.(price - price AT '1 Jun 2018');
> col_0
----------
0.10 USD
And the following code snipped shows how the time-operator AT is used to change the past pencil price at 1 June 2018 to 0.88 USD.
UPDATE pencil.price AT '1 Jun 2018' := 0.88 USD;
> update OK
Micro-versioning and time-operators completely relieve us programmers from manually allocating, maintaining, and looping over time-series.
I've implemented micro-versioning and a basic set of time-operators into the programming language that I'm currently working on (GLUE).
You can download a pre-alpha version here and play around with it. The demo is far from perfect, but it should give you an idea of what is possible.