3

A function (or any discrete block of code) can be considered as having various forms of "correctness" or "safety", for example if a function does not access or mutate any shared-state (or does so safely, e.g. using locks) then it is deemed "thread-safe". In C++, a function is "const-correct" if only the absolute minimum parameters lack the const modifier, and "type-safety" means the function does not rely on late-binding or dynamic behavior which could cause member-access fail at runtime.

Now consider a function which takes the value of "now", e.g. System.DateTime.UtcNow in .NET:

public static Resource CreateResource() {

    Resource ret = new Resource();
    ret.Created = DateTime.UtcNow;
    ret.Modified = DateTime.UtcNow;
    return ret;
}

The bug here is that the value of UtcNow could change between setting .Created and .Modified, so the two property values would be different, implying that the resource has been modified after it was created.

The correct implementation would cache the initial value of UtcNow so that the values of the two properties are guaranteed to be identical:

DateTime now = DateTime.UtcNow;

Resource ret = new Resource();
ret.Created = now;
ret.Modified = now;

Or alternatively:

Resource ret = new Resource();
ret.Modified = ret.Created = DateTime.UtcNow;
return ret;

What is the term to describe this "correctness"? I thought of "time-correct" or the slightly more pretentious "temporally-correct" or "chronologically-correct" but I wonder if those terms might imply something else.

5
  • 8
    I am pretty sure there is no widely accepted, general term for this, since this problem is a relatively seldom case, (compared to "const-correctness" or "thread-safety", which are terms applicable to a much wider range of programs and functions).
    – Doc Brown
    Aug 8, 2016 at 9:41
  • 3
    not the same but sort of related is referential transparency i.e. the fact that UtcNow is not referentially transparent causes you problems
    – jk.
    Aug 8, 2016 at 12:49
  • 3
    also another alternative solution would be to pass the value of now into CreateResource, which has the advantage that CreateResource can then be referentially transparent
    – jk.
    Aug 8, 2016 at 12:51
  • 1
    yeah I'd just call this a bug caused by thinking an impure function was pure. this is basically the same thing as var r = new Random(); var a = r.Next(); var b = r.Next(); and expecting a == b to be true.
    – sara
    Aug 8, 2016 at 14:34
  • 1
    and I agree with @jk. code accessing DateTime.Now directly is really really really cumbersome to test. it's like newing up a db connection or doing disk IO. hard dependencies that belong in a higher layer.
    – sara
    Aug 8, 2016 at 14:35

3 Answers 3

6

I am pretty sure there is no widely accepted, general term for this, since this problem is a relatively seldom case, compared to "const-correctness" or "thread-safety", which are terms applicable to a much wider range of programs and functions.

However, independent from the "time topic", the UtcNow function belongs to the wider class of so called impure functions. And since multiple calls of impure functions never guarantee to deliver the same result (even when called with the same input parameters), one always needs to be careful not to expect this kind of behaviour from impure functions, time functions are in no way special to this.

If I would need a term to describe this, I would probably say something like "CreateResource cares for atomic access when calling UtcNow".

1

There isn't a term for everything. Your example is simply incorrect because it uses a volatile value repeatedly under the assumption that it isn't.

This is a case where having a clear specification of what's expected of your function before writing it avoids those kinds of bugs.

Unclear: "The structure returned by function f() must have the creation and modification times set to the current UTC time." This is how your first example happens.

Clearer: "The structure returned by function f() must have the creation and modification times set to UTC time when the function began executing." That might lead you to write this:

timenow = DateTime.UtcNow;
ret.Created = timenow;
ret.Modified = timenow;

Clearest: "The structure returned by function f() must have the creation time set to UTC time when the function began executing and the modification time identical to the creation time." This is just as functional as the last one but cuts the amount of code by a third and has the added benefit of making what was specified apparent without having to to back and read the spec:

ret.Created = DateTime.UtcNow;
ret.Modified = ret.Created;
1

I'd say the best term that applies to this case is transactional—your CreateResource function acts in a way that depends on state, but it wants to see a consistent snapshot of that state as it existed at a single point in the program's execution.

This concept is familiar in relational databases, where transactions establish snapshots of the database's state in order to achieve isolation. The problem in your first example, cast into this terminology, is that your function wants to perform a repeatable read—one of the isolation levels defined in the SQL standards.

And in fact, repeatability of current time functions is a common feature in SQL databases. When a transaction is created the timestamp is recorded as part of its metadata, and all calls to functions like CURRENT_TIMESTAMP read their transaction's captured value. See for example this section of the PostgreSQL documentation:

Since these functions return the start time of the current transaction, their values do not change during the transaction. This is considered a feature: the intent is to allow a single transaction to have a consistent notion of the "current" time, so that multiple modifications within the same transaction bear the same time stamp.

PostgreSQL also provides functions that return the start time of the current statement, as well as the actual current time at the instant the function is called.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.