-
Notifications
You must be signed in to change notification settings - Fork 7
/
rebuttal.html
262 lines (232 loc) · 9.36 KB
/
rebuttal.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Rebuttal to Additional format specifiers for time_point</title>
<meta name="generator" content="BBEdit 14.6" />
</head>
<body>
<address align=right>
Document number: P3015D1
<br/>
Date: 2023-10-13
<br/>
Audience: Library Evolution Working Group
<br/>
Reply-to: <a href="mailto:howard.hinnant@gmail.com">Howard E. Hinnant</a><br/>
</address>
<hr/>
<h1 align=center>Rebuttal to Additional format specifiers for <code>time_point</code></h1>
<h2>Contents</h2>
<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#Bad">Having a standard specify run-time changes to existing code is
<b>Bad</b><sup>TM</sup></a></li>
<li><a href="#Existing">The <code>%S</code> flag as specified in the
<code><chrono></code> library is existing code</a></li>
<li><a href="#Good"><code>%S</code> is a good design</a></li>
<li><a href="#Acknowledgments">Acknowledgments</a></li>
<li><a href="#References">References</a></li>
</ul>
<a name="Introduction"></a><h2>Introduction</h2>
<p>
This paper is written to express strong opposition to changing the
meaning of <code>%S</code> as proposed in <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2945r0
.html">P2945R0</a>. To be perfectly clear, this paper expresses no
objection to adding syntax to specify precision to <code>%S</code> as
proposed in the <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2945r0
.html#less-preferred-proposal-wording">Less-Preferred Proposal
Wording</a>. This would not break any code. The only objection is to
changing the meaning of <code>%S</code> from representing seconds
exactly, to representing only the integral part of seconds as proposed
in the <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2945r0
.html#preferred-proposal-wording">Preferred Proposal Wording</a>.
</p>
<a name="Bad"></a><h2>
Having a standard specify run-time changes to existing code is
<b>Bad</b><sup>TM</sup>
</h2>
<p>
The proper way to change existing behavior in a standard is to
deprecate the existing behavior, and provide new syntax for the new
behavior. Let both behaviors coexist for a few cycles, then remove
the deprecated specification.
</p>
<p>
Doing otherwise risks introducing run-time errors to existing code by
simply upgrading to a new version of C++. Such run-time errors have
the potential for raising safety and security issues. It also
undermines the important claims about C++ being stable and standards
being backwards compatible.
</p>
<a name="Existing"></a><h2>
The <code>%S</code> flag as specified in the
<code><chrono></code> library is existing code
</h2>
<p>
It has been shipping in MSVC for over a year now.
</p>
<p>
It has been implemented in gcc 14.0.0.
</p>
<p>
<code>%S</code> has been documented by the standard, by books, by
countless informal articles and postings, and by my date library.
</p>
<p>
<code>%S</code> has 7 years of positive field experience with this
syntax and behavior in my date library.
</p>
<a name="Good"></a><h2>
<code>%S</code> is a good design
</h2>
<p>
The design of <code>%S</code> follows the principles first laid down
by the C++11 version of <code><chrono></code>.
<code><chrono></code> does not implicitly throw away
information. This is true in conversion of units, and it remains true
in formatting. All information is preserved unless truncating
behavior is explicitly requested. And when it is explicitly
requested, there exists options on which way to truncate: towards
zero, towards negative infinity, towards positive infinity, or to
nearest.
</p>
<p>
<code><chrono></code> was precision-neutral in C++11, and
remains so a decade later in C++23. <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.
htm#History">From N2661</a>, written 2008-06-11:
</p>
<blockquote>
<p>
This paper proposes a solution that is <i>precision neutral</i>.
</p>
</blockquote>
<p>
No single precision is promoted above others or given special
privileges. It is not up to <code><chrono></code> to decide
that one precision is better than another. That decision is up to the
OS which talks directly to the hardware. And up to the client, who
knows what precision is best for their application.
<code><chrono></code> is just a middleman to make the syntax
between the OS and the client portable.
</p>
<p>
Clients often change the OS’s precision to their specification’s
precision at the point of input, such as wrapping a call to now:
</p>
<blockquote><pre>
auto
GetCurrentTime()
{
using namespace std::chrono;
return floor<milliseconds>(system_clock::now());
}
void
foo()
{
auto tp = GetCurrentTime();
// ...
// maybe do some arithmetic or conversions to and from local time here
// ...
// Formatted with milliseconds precision as specified back in the implementation of GetCurrentTime()
datafile << std::format("{:%FT%TZ}", tp);
}
void
bar()
{
decltype(GetCurrentTime()) tp;
// Same format string (minus the "{:}") to parse it back in
datafile >> std::chrono::parse("%FT%TZ", tp);
}
</pre></blockquote>
<p>
And then traffic in those <code>time_point</code>s throughout their
library or application. There may be many points of both formatting
and parsing involved throughout their application. And at each point
they don’t have to worry about synchronizing their parse and format
statements with their specification’s precision. They can just ask
for the time: <code>“%F %T”</code> (etc.). And when their
specification changes, there is no pain point. Formatting and parsing
<em>by default</em> automatically adjust. Change
<code>milliseconds</code> to <code>seconds</code> in
<code>GetCurrentTime()</code> and things just work, but now at
seconds-precision. Change <code>floor</code> to <code>ceil</code> or
<code>round</code> to achieve alternative rounding modes from the
OS-supplied precision.
</p>
<p>
<code><chrono></code> does not (and should not) carry all of
this respect for the client around and then when the client gets ready
to create a logging statement suddenly say: Oh, you probably want the
precision a bunch of committee members decided upon. No,
<code><chrono></code> should give the client the precision they
have already asked for (as the default, of course there should be a
way to change it).
</p>
<p>
Clients also value symmetry between the parsing and formatting strings
so that they only have to learn one micro-language and not two.
During parsing <code>%S</code> takes its precision from the type being
parsed, and reads up to that amount of precision from the input
stream. A piece-wise redesign of <code><chrono></code> without
an in-depth knowledge of the entire library is foolhardy at best. And
in this case is also disruptive and dangerous.
</p>
<p>
<a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2945r0
.html">P2945R0</a> questions why the current spec offers fractional
seconds, but not fractional minutes or hours. The answer<sup><a
href="#ref1">1</a></sup> dates back to Egyptians who divided the day
into 12 periods around B.C. 1500. At that time no one cared enough
about fractional hours to invent a system for them. Hours were not
divided into minutes until the first mechanical clocks that displayed
minutes appeared near the end of the 16th century. Minutes were
defined as <sup>1</sup>/<sub>60</sub> of an hour based on the
sexagesimal system developed by the Sumerians around 2000 B.C. This
was used many centuries later first to divide circles, and later to
divide the round mechanical clock faces. Minutes were subsequently
divided using the sexagesimal system into seconds. In the 1500s
seconds were not displayed on the clock face but rather measured by
swings of the pendulum.
</p>
<p>
It was not until the late 19<sup><i>th</i></sup> or early
20<sup><i>th</i></sup> century that technology advanced enough for
people to even consider dividing seconds. And at that time,
civilization chose to use the base 10 system which had become well
established. And this is why hours are divided by minutes, minutes by
seconds, and seconds by powers of 10. It is simply history.
</p>
<p>
Nevertheless, if someone really wants fractional hours, that is certainly doable:
</p>
<blockquote><pre>
duration<double, hours::period> d = ...
cout << format("{:.4}, d) << '\n';
</pre></blockquote>
<p>
Finally <code>%S</code> does not need to have identical functionality
to other languages as argued by <a
href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2945r0
.html">P2945R0</a>. There are many ways in which
<code><chrono></code> differs from other date time libraries.
These differences are what makes the <code><chrono></code>
solution superior, in safety, functionality and performance.
</p>
<a name="Acknowledgments"></a><h2>Acknowledgments</h2>
<p>
Thank you to Tomasz Kamiński, Stephan T. Lavavej, David Sankel, Bjarne
Stroustrup, Alan Talbot, David Vandevoorde, and Ville Voutilainen for
the corrections, suggestions and comments. This paper improved from
its original draft because of your generously donated time and
attention.
</p>
<a name="References"></a><h2>References</h2>
<a name="ref1"><sup>1</sup> <a href="https://www.scientificamerican.com/article/experts-time-division-days-hours-minutes/">Why is a minute divided into 60 seconds, an hour into 60 minutes, yet there are only 24 hours in a day?</a>
</body>
</html>