11

With C++11, C++ has some timing facilities in the standard. One of these facilities is a standard interface for clocks, that basically allows getting the time at the call of the now function of the clock.

All is well up until this point but I fail to see the reason for requiring now to be a static function. On a hosted system, the standard clocks might be implementable purely with system calls or by reading the processor counters etc. However, this limits the implementation of custom clocks that needs to maintain some state. With this interface, one either cannot implement some clocks or has to use global state.

One issue I ran into was basically synchronizing a local clock to the time I got from an NTP server. The code simply looks like this:

class sntp_clock
{
public:
    sntp_clock() 
        : local_time_at_ctor(read_some_cpu_counter())
        , sntp_time_at_ctor(read_sntp_time()) {}
 
    sntp_time_t now() const {
        return sntp_time_at_ctor + (read_some_cpu_counter() - local_time_at_ctor);
    }

    /* required types etc */

private:
    local_time_t local_time_at_ctor;
    sntp_time_t sntp_time_at_ctor;
};

Since I can't make now static without making the state static as well, this clock does not satisfy the requirements of a Clock in C++ standard. But each NTP server will have separate state.

Additionally, for efficiency reasons, I may not want to start the cpu counter a clock instance exists, but again, since now is static, I can't know exactly when to start to clock, or when to stop it.

My question is why do clocks have static now requirement?

Note: The current standard draft requires now to be static: http://eel.is/c++draft/time.clock.req#tab:time.clock

Boost.Chrono documentation has the same requirement: https://www.boost.org/doc/libs/1_63_0/doc/html/chrono/reference.html#chrono.reference.cpp0x.clock

Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
Fatih BAKIR
  • 2,499
  • 1
  • 13
  • 18
  • It has to be `static` because that's what the standard dictates. If the standard dictated something else, it'd have to be something else. Presumably this is to simplify usage. What kind of clock needs to maintain state? – tadman May 31 '19 at 18:57
  • 7
    @tadman I think the question is asking *why* the committee chose to write the standard that way. – François Andrieux May 31 '19 at 18:59
  • @FrançoisAndrieux Time for the `[language-lawyer]` tag? – tadman May 31 '19 at 18:59
  • @tadman Doesn't feel like it to me. It's not a question about interpreting the language. May be too broad or opinion based if no solid source like a defect report can be found. – François Andrieux May 31 '19 at 19:00
  • 2
    @tadman, I want to know the reasoning behind the decision though. _Technically_ all clocks have some state. Just that the OS is maintaining that state for you. On our embedded OS, I have to implement the clocks, and I wanted to make them compatible with the C++ standard. – Fatih BAKIR May 31 '19 at 19:01
  • 2
    Because the `now` function doesn't use any existing clock object to calculate the "now" time? Therefore it doesn't need to a non-static member function. It could even be a non-member function. – Some programmer dude May 31 '19 at 19:01
  • It's worth rephrasing the question then to say "Why does the C++ Clock standard require now() be static?" or something to that effect. This avoids the accidental tautology. – tadman May 31 '19 at 19:02
  • @FatihBAKIR The reasoning may be that each clock represents some passage of time (real or virtual) that is consistent for a given kind of clock. It makes sense when consider GPS or wall clock times. But it doesn't seem to account for virtual clocks may only want to be consistent on a per-instance basis. Perhaps such a use case was just not considered, or was deemed not worth supporting. I agree that it seems like an oversight. It wouldn't be so bad to have to do `std::chrono::system_time{}.now();` or simply having a `static` member do that. – François Andrieux May 31 '19 at 19:03
  • Note that there are a lot of other deficiencies involving C++11 time concept - notably, you can't implement clocks that advance at different rates even if the rate is a constant. Note that `clock_getcpuclockid` in particular cannot be wrapped. – o11c May 31 '19 at 19:06
  • 1
    @FrançoisAndrieux, I agree. In fact, I'm wondering if limitation could be removed in a future standard. They could've even made one or more global clock instances if they wanted to enforce statelessness (or global state), like `std::cout`: `std::system_clock.now()`. – Fatih BAKIR May 31 '19 at 19:07
  • Aren't you asking the wrong people? The standards committee members are not here. – Robert Harvey May 31 '19 at 19:08
  • 3
    @RobertHarvey, I know for certain Howard Hinnant is here. Besides, if we get an answer, I'd like to have it here for other people who might wonder about the same to see. – Fatih BAKIR May 31 '19 at 19:09
  • Maybe you should ask him, directly. – Robert Harvey May 31 '19 at 19:09
  • 2
    @FatihBAKIR: "*In fact, I'm wondering if limitation could be removed in a future standard.*" No, it could not. All of the template code written expecting a `Clock` will expect it to have a static `now` function. And thus would break on a non-static one. – Nicol Bolas May 31 '19 at 19:09
  • @NicolBolas a man can dream though :) – Fatih BAKIR May 31 '19 at 19:10
  • 2
    @FatihBAKIR Remember, there's a [procedure](https://isocpp.org/std/submit-a-proposal) for submitting proposals if you care to contribute. Worst case, your proposal is rejected and you learn the answer to your question. – François Andrieux May 31 '19 at 19:14
  • 1
    btw, you *can* use the singleton pattern (which won't start the clock until first use) as seen [here](https://stackoverflow.com/questions/1008019/c-singleton-design-pattern) – kmdreko May 31 '19 at 19:16
  • To me it looks like `now()` should have been a free function, but then it couldn't be in the appropriate namespace. Thus, making it a static member puts in in the appropriate namespace. – Nikos C. May 31 '19 at 19:16
  • @NikosC., as I said, making such things global prevents the implementation of some clocks – Fatih BAKIR May 31 '19 at 19:17
  • @FatihBAKIR I don't disagree. I'm just saying that to me it looks like they wanted it to be a free function, that's why it ended up as a static :-) – Nikos C. May 31 '19 at 19:22
  • @NikosC., oh sorry, my bad – Fatih BAKIR May 31 '19 at 19:22
  • @FatihBAKIR: Is it reasonable for different `sntp_clock` instances to give different counts, to essentially have different epochs? Is that a useful thing to have? Doesn't that mean you'd need to carry around the specific `sntp_clock` instance in order to be able to comprehend a particular `now` return value? – Nicol Bolas May 31 '19 at 19:39
  • 1
    System clocks are static entities and so the standard *should* dictate that they are accessible by *static* means. And why should you have to create an object to use a static resource? That doesn't prevent you creating your own system of state based clocks **on top of** the standard facilities. – Galik May 31 '19 at 19:40
  • Why does every _instance_ of your clock need separate state? Do they return different values? – Mooing Duck Aug 30 '20 at 02:58
  • 1
    @MooingDuck, it's an sntp clock, so if you have clocks with different servers, they may very well return different values. – Fatih BAKIR Sep 01 '20 at 18:17

1 Answers1

25

There were both theoretical and practical concerns that drove this decision.

The Theoretical

There's a joke that a person with a watch always knows what time it is, but a person with two watches never does. There's just a little bit of truth in that joke, and it did influence the decision. If an application needs to know the current time in two or more places, and if clocks are stateful, then there is an issue in ensuring that the same instance of the clock be used in all places to ensure that all parts of the code are dealing with the same definition of "current time."

By making clocks stateless, but allowing multiple clocks with different types, the type system can help the programmer ensure that a program uses the same definition of current time in different places of the program. And yet in those cases where one needs multiple definitions of time, then that too is available, just as distinct types.

The Practical

As more of a practical consideration, the very first clients of the chrono::clock code was chrono itself. We had to eat our own dog food. Take for example an implementation of condition_variable::wait_until:

https://github.com/llvm-mirror/libcxx/blob/master/include/__mutex_base#L377-L385

template <class _Clock, class _Duration>
cv_status
condition_variable::wait_until(unique_lock<mutex>& __lk,
                               const chrono::time_point<_Clock, _Duration>& __t)
{
    using namespace chrono;
    wait_for(__lk, __t - _Clock::now());
    return _Clock::now() < __t ? cv_status::no_timeout : cv_status::timeout;
}

Here a function is taking a single generic time_point, and the algorithm needs to find the current time associated with that time_point. By packing the type of the Clock into the type of the time_point and by having a static now(), the code is very clean to write, and has a very clean interface. Yet it is generic enough that this code will work with any user-written custom clock: not just the std-specified clocks.

Had clocks been stateful, then either:

  1. condition_variable::wait_until could not get the current time, or
  2. The client would have to pass in the clock the time_point is measured against as well.

Neither of the above two choices seemed palatable to me.

Note that condition_variable::wait_until is not a special case, but just one example out of many such algorithms. Indeed, I assumed that not only standards implementors would write such algorithms, but the general public would too. Here's an example of the latter:

https://stackoverflow.com/a/35293183/576911


Yes, I have run into cases where people want stateful clocks. The OP of this question offers such an example. But since there is the option that "stateful clocks" can still be given static state, and if you need other state, use a different type; And because of the advantages of stateless clocks stated above; The choice was made that the advantage lay with the stateless clock design.


Update 1

I've been thinking more about the client that says:

So is my stateful clock not good code?

I think a stateful clock is fine as long as one realizes the limitations that are on it. And unfortunately I believe this is an issue that is more complicated than needs be because of a minor bug in the standard.

From a practical standpoint, there's only one thing you can't do with a stateful clock that you can do with a stateless clock, and it goes back to the section above titled The Practical.

You can not instantiate an algorithm (std or otherwise) that requires a template parameter to be a ClockTM.

For example if you have a time_point based on a stateful clock, you can not use that time_point to call condition_variable::wait_until. If you don't want to do that anyway, that doesn't mean your stateful clock is bad. If your stateful clock serves your purposes, then that is fine.

In C++20, there's even an example of a clock that doesn't meet all of the C++11-17 clock requirements:

struct local_t {};

Yes, that is (sort of) a clock. But it doesn't do anything, almost. It is used to create a family of time_points that have no associated now():

template<class Duration>
    using local_time  = time_point<local_t, Duration>;

And this turns out to be really useful when distinguishing UTC time points from time points that are associated with an as-yet-unspecified time zone (think type safety).

So if creating a clock without a static now() is ok for the standard, why isn't it ok for you?! And the only reason I can think of is that "minor bug" in the standard I reference above.

27.6 [time.point] in the C++20 spec says this about template<class Clock, class Duration> class time_point:

1 Clock shall either satisfy the Cpp17Clock requirements (27.3) or be the type local_t.

I now believe this is overly restrictive. Programmers ought to be able to instantiate time_point with a stateful clock. They just can't call condition_variable::wait_until (et al.) with that time_point. But they can still get all of the algebraic benefits of using that time_point and the durations resulting from its differences.

There's no good reason for this restriction except for the standard saying so. And the very existence of local_t which also doesn't meet the Cpp17Clock requirements pretty much proves the point.

1 Clock shall either satisfy the Cpp17Clock requirements (27.3) or be the type local_t have the nested type duration if the instantiation defaults the template parameter Duration.

Update 2

There is now a paper tracking this issue.

Update 3

The proposed changes are now in the working draft for the standard after C++20:

http://eel.is/c++draft/time.point.general

http://eel.is/c++draft/thread.req.paramname

Much thanks to Alexey Dmitriev for driving this work.

Howard Hinnant
  • 179,402
  • 46
  • 391
  • 527
  • 7
    It's great that you saw and answered this. I was just reading through [N2661](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm#Clocks) to see if it was in there and came up with the same conclusions. Thanks for your... *time* ;) – NathanOliver May 31 '19 at 19:46
  • 3
    I wish I would have had the forethought (and _time_) to put this rationale into [N2661](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm). It was a busy time for me, and there was hardly time to write down everything that needed to be written down. – Howard Hinnant May 31 '19 at 19:48
  • You don't mention this, and I think it is an underappreciate feature of static functions that is that it allows interfaces to be generalized to stateful objects and the same interface works, e.g. `template void f(FancyClock c){... c.now();}` (works for both static o member function `now()`, `c` can be stateful or not ). Had anything like this to do with the choice (or more exactly, reference-implementing) a library function as static? – alfC May 06 '21 at 03:15
  • That's a good point. I've known about this feature of the language. But I don't have a specific motivating use case of this language feature in a generic function for time_points or clocks. I have seen code written for stateful clocks that could possibly work for stateless clocks because of this language feature. But such code wasn't really generic. I agree this is an under appreciated feature of the language (to be able to call static member functions with the `obj.` syntax). – Howard Hinnant May 06 '21 at 03:22