[Development] <chrono> first (was: Re: C++20 @ Qt)

Marc Mutz marc.mutz at qt.io
Mon Jan 23 14:06:13 CET 2023


Hi,

TL;DR:
- don't use qin64 for durations
- use QDeadlineTimer for timeouts
- use chrono::{milli,micro,nano,}seconds for everything that doesn't have Forever state
- don't implement chrono via integer overloads, do it the other way around 

Not really C++20, rather C++11, but let's keep the C++ stuff together.

Since 2018, in QTBUG-67383, we have users complaining about the limited 
range of int milliseconds arguments:

 > Now QTimer::start(int msec) accepts only int values which corresponds
 > to ~ 24 days as maximum time interval.

Instead of changing to qint64 timeouts, as suggested, we should use 
chrono types. Here's why:

- we do have QDeadlineTimer, which implicitly converts from chrono
   types, but
   - it has a Forever state, which is meaningful for timeouts, but not
     for intervals (QTimer with Forever interval?).
   - it's name doesn't exactly lend itself for use in APIs (why pass a
     timer to a timer?) 
   - it always has nanosecond resolution. Most of our APIs have
     millisecond resolution. Unless we want to change them all to ns
     resolution, any function using QDT must document the real
     granularity of the duration, and the rounding mode from ns. In
     contrast, passing 1ns to a function taking chrono::milliseconds
     simply fails to compile,forcing the caller to be explicit about what
     he wants (chrono::floor, chrono::ceil, duration_cast,  ...).
- we do support chrono types in many APIs, and we want to support them
   in all APIs that deal with duration, as 1s is just so much more expressive
   than '1000'. The integer-based APIs should be considered legacy
   support. At some point, we might want to deprecate them, and then the
   chrono overloads become the main implementation, anyway, so we might
   just go there directly.
- if we take qint64, then internally have to construct a chrono type
   from it, it means Qt code is responsible for checking for overflow
   (chrono::milliseconds need not support the full 64-bit range),
   creating an artificial error state that wouldn't exist if we only
   accepted chrono types.
- if we take a chrono type, then shoehorn it through a legacy int
  overload, we lose the range provided by the chrono types and
  requested by users

So, chrono types are
- more future-proof
- safer (both as in less possible errors in the implementation, as well
   as more type-safe in the caller)
- self-explanatory (w.r.t. granularity)
- more expressive

So, I suggest to port all duration-related APIs to <chrono>, and make 
<chrono> the primary implementation, not vice versa. In any case, ndo ot 
add 64-bit timeouts (ns granularity like QDeeadlineTimer is ok, because 
std::chrono::nanoseconds has at least a 64-bit representation). Do not 
add new integer-based duration properties. Use QDeadlineTimer if 
'Forever' is a valid value (e.g. timeouts).

There's no rush, we need to get the plumbing in QtCore right, first.

Comments?

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at qt.io>
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B



More information about the Development mailing list