forked from HowardHinnant/papers
-
Notifications
You must be signed in to change notification settings - Fork 5
/
return_directv2.html
814 lines (703 loc) · 26.1 KB
/
return_directv2.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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Response To: Let return Be Explicit</title>
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
background-color:#E0E0E0;
padding-left: 15px;
padding-right: 15px;
padding-top: 1px;
padding-bottom: 1px;
}
ins {color:#00A000}
del {color:#A00000}
</style>
</head>
<body>
<address align=right>
Document number: D????
<br/>
<br/>
<a href="mailto:[email protected]">Ville Voutilainen</a><br/>
<a href="mailto:[email protected]">Mikael Kilpeläinen</a><br/>
<a href="mailto:[email protected]">Jonathan Wakely</a><br/>
2014-10-10<br/>
</address>
<hr/>
<h1 align=center>Response To: Let <code>return {expr}</code> Be Explicit</h1>
<h2>Abstract</h2>
<p>We think N4074 needs to be shelved; it's doubtful whether it's an issue
common and major enough to warrant a core language addition; it's more doubtful
whether it's major enough to warrant a core language <b>change</b>. We do
not know how much code such a change will break, and there are potential
teachability problems with the proposal. There are seemingly palatable
existing alternative solutions, and it's likely that there are more
palatable alternative core language additions that do not change or confuse
existing semantics.
<h2>Contents</h2>
<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#Example">The Counter-Example</a></li>
<li><a href="#ExistingCode">Does anyone actually use curly braces on <code>return</code>?</a></li>
<li><a href="#ExampleTuple">The <code>tuple</code> Counter-Example</a></li>
<li><a href="#AnotherExample">Another Example</a></li>
<li><a href="#MoreSmartPointers">More about smart pointers</a></li>
<li><a href="#Illogical">Choosing braces to mean "non-explicit" is illogical</a></li>
<li><a href="#Breakage">Breaking existing code</a></li>
<li><a href="#RemainingRepeatsOfReturnType">Are there still cases where the return type must be repeated anyway?</a></li>
<li><a href="#Alternative">Alternative solutions</a></li>
<li><a href="#Summary">Summary</a></li>
</ul>
<a name="Introduction"></a><h2>Introduction</h2>
<p>
This paper is a revision of <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4094.html">N4094</a> with kind permission from Howard Hinnant. It is in response to:
</p>
<blockquote><p>
<a href="https://isocpp.org/files/papers/n4074.pdf">N4074: Let <code>return {expr}</code> Be Explicit</a>
</p></blockquote>
<p>
N4074 proposes (with the best of intentions) to ignore the
<code>explicit</code> qualifier on conversions when the conversion would take
place on a <code>return</code> statement and is surrounded with curly braces.
For example:
</p>
<blockquote><pre>
struct Type2
{
<ins>explicit</ins> Type2(int) {}
};
Type2
makeType2(int i)
{
return {i}; // error now, ok with adoption of N4074.
}
</pre></blockquote>
<p>
Note that this code today results in a compile-time error, not because of the
braces, but because of the <code>explicit</code> qualifier on the <codeType2</code>
constructor taking an <code>int</code>. Remove that <code>explicit</code>
qualifier as in the example below, and the code compiles today:
</p>
<blockquote><pre>
struct Type1
{
<del>explicit</del> Type1(int) {}
};
Type1
makeType1(int i)
{
return {i}; // ok since C++11, implicit conversion from int to Type1
}
</pre></blockquote>
<p>
The motivation for this change comes from the original of N4074,
<a href="https://isocpp.org/files/papers/n4029.pdf">N4029</a>:
</p>
<blockquote>
<p>
I believe this is inconsistent because the named return type is just as
"explicit" a type as a named local automatic variable type. Requiring the
user to express the type is by definition redundant — there is no other
type it could be.
</p>
<p>
This is falls into the (arguably most) hated category of C++ compiler
diagnostics: "I know exactly what you meant. My error message even tells you
exactly what you must type. But I will make you type it."
</p>
</blockquote>
<p>
We can relate. Unnecessary typing <i>is</i> frustrating. However we believe
it is possible that ignoring the <code>explicit</code> qualifier on type
conversions, even if only restricted to <code>return</code> statements
enclosed with curly braces, could turn <i>compile-time</i> errors into
<i>run-time</i> errors. Possibly <i>very subtle run-time</i> errors (the
worst kind).
</p>
<p>
How likely is it that such run-time errors might be introduced?
<i><shrug></i> Such conjecture is always highly speculative. But in this
instance, we can offer a realistic example where exactly this would happen.
And it happens very close to our home: by ignoring the <code>explicit</code>
qualifier of the constructor of a <b>std-defined</b> class type.
</p>
<a name="Example"></a><h2>The Counter-Example</h2>
<p>
Bear with us while we set up the likelihood of this counter-example actually
happening in the wild...
</p>
<p>
Today in <code><string></code> we have the following functions which
turn a <code>std::string</code> into an arithmetic type:
</p>
<blockquote><pre>
int stoi (const string& str, size_t* idx = 0, int base = 10);
long stol (const string& str, size_t* idx = 0, int base = 10);
unsigned long stoul (const string& str, size_t* idx = 0, int base = 10);
long long stoll (const string& str, size_t* idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t* idx = 0, int base = 10);
float stof (const string& str, size_t* idx = 0);
double stod (const string& str, size_t* idx = 0);
long double stold(const string& str, size_t* idx = 0);
</pre></blockquote>
<p>
It seems quite reasonable that a programmer might say to himself:
</p>
<blockquote>
<p>
I would like to write a function that turns a <code>std::string</code> into
a <code>std::chrono::duration</code>.
</p>
</blockquote>
<p>
Which <code>duration</code>? Well, let's keep it simple and say: any one of
the six "predefined" <code>duration</code>s: <code>hours</code>,
<code>minutes</code>, <code>seconds</code>, <code>milliseconds</code>,
<code>microseconds</code>, or <code>nanoseconds</code> can be parsed and
returned as <code>nanoseconds</code>.
</p>
<p>
What would be the syntax for doing this? Well, it would be quite reasonable
to follow the same syntax we already have for <code>duration</code> literals:
</p>
<blockquote><pre>
2h // 2 hours
2min // 2 minutes
2s // 2 seconds
2ms // 2 milliseconds
2us // 2 microseconds
2ns // 2 nanoseconds
</pre></blockquote>
<p>
And here is quite reasonable code for doing this:
</p>
<blockquote><pre>
std::chrono::nanoseconds
stons(std::string const& str)
{
using namespace std::chrono;
auto errno_save = errno;
errno = 0;
char* endptr;
auto count = std::strtoll(str.data(), &endptr, 10);
std::swap(errno, errno_save);
if (errno_save != 0)
throw std::runtime_error("error parsing duration");
if (str.data() < endptr && endptr < str.data() + str.size())
{
switch (*endptr)
{
case 'h':
return hours{count};
case 'm':
if (endptr + 1 < str.data() + str.size())
{
switch (endptr[1])
{
case 'i':
if (endptr + 2 < str.data() + str.size() && endptr[2] == 'n')
return {count};
break;
case 's':
return milliseconds{count};
}
}
break;
case 's':
return seconds{count};
case 'u':
if (endptr + 1 < str.data() + str.size() && endptr[1] == 's')
return microseconds{count};
break;
case 'n':
if (endptr + 1 < str.data() + str.size() && endptr[1] == 's')
return nanoseconds{count};
break;
}
}
throw std::runtime_error("error parsing duration");
}
</pre></blockquote>
<p>
Here is a simplistic "are you breathing" test for this code:
</p>
<blockquote><pre>
int
main()
{
using namespace std;
using namespace std::chrono;
cout << stons("2h").count() << "ns\n";
cout << stons("2min").count() << "ns\n";
cout << stons("2s").count() << "ns\n";
cout << stons("2ms").count() << "ns\n";
cout << stons("2us").count() << "ns\n";
cout << stons("2ns").count() << "ns\n";
}
</pre></blockquote>
<p>
Ok, so what is our point?
</p>
<p>
There is a careless type-o / bug in <code>stons</code>. Do you see it yet?
<code>stons</code> is not trivial. But neither is it horribly complicated.
Nor is it contrived. Nor is the bug in it contrived. It is a type of bug
that occurs commonly.
</p>
<p>
Today the bug in <code>stons</code> results in a compile-time error. This
compile-time error was intended by the designers of the
<code><chrono></code> library.
</p>
<p>
If we accept N4074, the bug in <code>stons</code> becomes a run-time error.
Have you spotted it yet? Here is a clue. The output of the test (with
N4074 implemented) is:
</p>
<blockquote><pre>
7200000000000ns
2ns
2000000000ns
2000000ns
2000ns
2ns
</pre></blockquote>
<p>
The error is this line that parses "min" after the count:
</p>
<blockquote><pre>
return {count};
</pre></blockquote>
<p>
which should read:
</p>
<blockquote><pre>
return minutes{count};
</pre></blockquote>
<p>
Once the error is corrected, the correct output of the test is:
</p>
<blockquote><pre>
7200000000000ns
120000000000ns
2000000000ns
2000000ns
2000ns
2ns
</pre></blockquote>
<a name="ExistingCode"></a><h2>Does anyone actually use curly braces on <code>return</code>?</h2>
<p>
The expression <code>return {x};</code> has only been legal since C++11.
There have only been 3 (official) years for it to be adopted by programmers.
Is there any evidence anyone is actually using this syntax?
</p>
<p>
Yes.
</p>
<ul>
<li><a href="https://github.com/facebook/rocksdb/blob/master/db/table_properties_collector.cc#L42">rocksdb</a></li>
<li><a href="https://github.com/facebook/rocksdb/blob/master/table/block_based_table_reader.cc#L727">rocksdb</a></li>
<li><a href="https://github.com/facebook/rocksdb/blob/master/table/block_based_table_reader.cc#L732">rocksdb</a></li>
<li><a href="https://github.com/facebook/rocksdb/blob/master/table/block_based_table_reader.cc#L779">rocksdb</a></li>
<li><a href="http://stackoverflow.com/search?q=%5Bc%2B%2B11%5D+%22return+%7B%22">98 hits on stackoverflow</a></li>
<li><a href="http://codereview.stackexchange.com/search?q=%5Bc%2B%2B%5D+%22return+%7B%22">15 hits on Code Review</a></li>
</ul>
<p>
These were just the ones we were able to find. Searching for
<code>"return[\s]*{"</code> is exceedingly challenging. But just the above
results clearly demonstrate a use that is significantly greater than
"vanishingly rare."
</p>
<a name="ExampleTuple"></a><h2>The <code>tuple</code> Counter-Example</h2>
<p>
What if the return isn't a scalar? For example is this just as unsafe?
</p>
<blockquote><pre>
return {5, 23};
</pre></blockquote>
<p>
If the return type is <code>tuple<seconds, nanoseconds></code> (which
we still do not want to construct implicitly from <code>int</code>), then
this would <b>definitely not</b> be safe!
</p>
<p>
We never want to implicitly construct a <code>duration</code> from an
<code>int</code>. Here is how we say that in C++:
</p>
<blockquote><pre>
template <class Rep2> constexpr <b>explicit</b> duration(const Rep2& r);
</pre></blockquote>
<p>
That is, we put <code>explicit</code> on the constructor (or on a conversion
operator). To change the language to ignore <code>explicit</code> in some
places is a dangerous direction.
</p>
<p>
All that being said, if the constructions are <i>implicit</i> then they are
safe. For example:
</p>
<blockquote><pre>
tuple<seconds, nanoseconds>
test1()
{
return {3, 4}; // unsafe, 3 does not implicitly convert to seconds
// 4 does not implicitly convert to nanoseconds
}
tuple<seconds, nanoseconds>
test2()
{
return {3h, 4ms}; // safe, 3h does implicitly convert to seconds
// 4ms does implicitly convert to nanoseconds
}
tuple<int, float, string>
test3()
{
return {3, 4.5, "text"}; // safe, 3 does implicitly convert to int
// 4.5 does implicitly convert to float
// "text" does implicitly convert to string
}
</pre></blockquote>
<p>
None of the three examples compile today according to C++14 because the
<code>std::tuple</code> constructor invoked is marked <code>explicit</code>.
However <code>test2</code> and <code>test3</code> are both perfectly safe. It
is unambiguous what is intended in these latter two cases. And they would
indeed compile if the <code>tuple</code> constructor invoked was not marked
<code>explicit</code>.
</p>
<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3739.html">N3739</a>
is a proposal which makes <code>test2</code> and <code>test3</code> legal,
while keeping <code>test1</code> a compile-time error. We fully support this
proposal. Indeed Howard implemented this proposal in <a
href="http://libcxx.llvm.org">libc++</a> years ago, for precisely the same
reasons that N4074 is now proposed: To ease the syntax burden on the
programmer. But unlike N4074, N3739 never disregards the <code>explicit</code>
keyword that the programmer has qualified one of his constructors with.
</p>
<a name="AnotherExample"></a><h2>Another Example</h2>
<p>
Perhaps there is some defective quality about <code>chrono::duration</code>
which is causing the problem. Is <code>chrono::duration</code> the <i>only</i>
problematic example?
</p>
<p>
Consider a class <code>OperatesOnData</code>.
</p>
<blockquote><pre>
class OperatesOnData
{
public:
OperatesOnData(VerifiedData); // knows that the Data has been verified
// Use this constructor ONLY with verified data!
explicit OperatesOnData(Data); // trusts that the Data has been verified
};
</pre></blockquote>
<p>
<code>Data</code> that comes from untrusted sources must first be verified to
make sure it is in the proper form, all invariants are met, etc. This
unverified <code>Data</code> is verified with the type <code>VerifiedData</code>.
This <code>VerifiedData</code> can then be safely sent to <code>OperatesOnData</code>
with no further verification.
</p>
<p>
However verifying the data is expensive. Sometimes <code>Data</code> comes
from a trusted source. So the author of <code>OperatesOnData</code> has set
up an <b>explicit</b> constructor that takes <code>Data</code>. Clients know
that <code>OperatesOnData</code> can't verify <code>Data</code> all
the time because of performance concerns. So when they know that their
<code>Data</code> need not be verified, they can use an explicit conversion
to <code>OperatesOnData</code> to communicate that fact.
</p>
<p>
Is this the best design in the world? That's beside the point. This is a
reasonable design one might find coded in C++.
</p>
<p>
Now we need to get the <code>Data</code> and start working on it:
</p>
<blockquote><pre>
VerifiedData getData();
OperatesOnData
startOperation()
{
return {getData()};
}
</pre></blockquote>
<p>
So far so good. This is valid and working C++14 code.
</p>
<p>
Three years go by, and the programmers responsible for this code change.
C++17 decides that making <code>return {x};</code> bind to explicit
conversions is a good idea.
</p>
<p>
Now, because of some changes on the other side of a million line program,
it is now too expensive for <code>getData()</code> to do the verification as
it has acquired some new clients that must do verification anyway. So
<code>getData()</code> changes to:
</p>
<blockquote><pre>
Data getData();
</pre></blockquote>
<p>
Bam. Unverified data gets silently sent to <code>OperatesOnData</code>.
The original code was designed <i>precisely</i> to catch this very error
<i>at compile time</i>.
</p>
<blockquote><pre>
Data getData();
OperatesOnData
startOperation()
{
return {getData()};
}
test.cpp:23:12: error: chosen constructor is explicit in copy-initialization
return {getData()};
^~~~~~~~~~~
test.cpp:14:14: note: constructor declared here
explicit OperatesOnData(Data); // trusts that the Data has been verified
^
1 error generated.
</pre></blockquote>
<p>
But because the committee has redefined what <code>return {getData()}</code>
means between C++11 and C++17 (a period of 6 years), a serious run time error
(perhaps a security breach) has been created.
</p>
<p>
This example highlights the fact that the return type of an expression is not
always clear at the point of the <code>return</code> statement, nor in direct
control of the function author. When what is being returned is the result of
some other function, declared and defined far away, there is potential for
error. If explicit conversions are implicitly allowed between these two
independently written pieces of code, the potential for error increases
greatly:
</p>
<blockquote><pre>
shared_ptr<BigGraphNode>
makeBigGraphNode()
{
return {allocateBigGraphNode()};
}
</pre></blockquote>
<p>
What type does <code>allocateBigGraphNode()</code> return? Today, if this
compiles, we are assured that it is some type that is implicitly convertible
to <code>shared_ptr<BigGraphNode></code>. Implicit conversions are
conversions that the author of <code>shared_ptr</code> deemed safe enough that
the conversion need not be explicitly called out at the point of use.
</p>
<p>
Explicit conversions on the other hand are not as safe as implicit conversions.
And for whatever reasons, the author of <code>shared_ptr</code> deemed the
conversions of some types to <code>shared_ptr</code> sufficiently dangerous
that they should be called out explicitly when used.
</p>
<p>
We ask again: What type does <code>allocateBigGraphNode()</code> return?
</p>
<p>
The answer today is that we don't know without further investigation, but it
is some type that implicitly converts to
<code>shared_ptr<BigGraphNode></code>. And we think that is a much
better answer than "some type that will convert to
<code>shared_ptr<BigGraphNode></code> explicitly or implicitly." This
latter set includes <code>BigGraphNode*</code>. If the above code is written
today, and the meaning of that return statement changes tomorrow. And the next
day the return type of <code>allocateBigGraphNode()</code> changes, there is a
very real potential for turning compile-time errors into run-time errors.
</p>
<p>
The above potential for error is <b>exactly</b> the same as it is for this
code:
</p>
<blockquote><pre>
void acceptBigGraphNode(shared_ptr<BigGraphNode>);
// ...
acceptBigGraphNode(allocateBigGraphNode());
</pre></blockquote>
<p>
If performing explicit conversions is dangerous in one of the above two
examples, then it is dangerous in both. The presence of curly braces in the
first example makes zero difference, as illustrated by the <code>stons</code>
example. Indeed, the presence of curly braces is today legal in the second
example:
</p>
<blockquote><pre>
acceptBigGraphNode({allocateBigGraphNode()});
</pre></blockquote>
<p>
but only <b>if</b> the conversion is implicit.
</p>
<a name="MoreSmartPointers"</a><h2>More about smart pointers</h2>
<p>
In <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4029.pdf">N4029</a>, Sutter responds to the concerns about implicit ownership transfer by saying "it's okay", and continues</p>
<p>
<blockquote>
I believe <code>return p;</code> is reasonable "what else could I possibly
have meant" code, with the most developer-infuriating kind of diagnostic
(being able to spell out exactly what the developer has to redundantly
write to make the code compile, yet forcing the developer to type
it out), and I think that it's unreasonable that I be forced to repeat
<code>std::unique_ptr<T>{}</code> here.
</blockquote>
</p>
<p>
It's not at all clear that it's "obvious" what the programmer meant. It's
NOT about knowing the <b>return</b> type. It's about knowing the <b>source</b>
type and its semantics. As it happens, with a raw pointer, we do not know
its ownership semantics, because it doesn't have any. We do not know where
it came from - it may be a result of a malloc inside a legacy API. It may
be a result of a strdup (same difference, really). It might not be a
pointer to a resource dynamically-allocated with a <code>default_delete</code>-compatible
allocator.
</p>
<p>
The implementation diagnostic is not saying "write the following boiler-plate".
It's saying "stop and think". It's specifically saying "you're about to
cross the border between no ownership semantics and strict ownership semantics,
please make sure you're doing what you think you're doing".
</p>
<p>
It also seems questionable that we would break the design expectations
of smart pointers well older than a decade just to make interfacing with
legacy raw pointers easier. Modern C++ code uses <code>make_unique</code> and <code>make_shared</code>,
not plain <code>new</code>. And such modern C++ code uses smart pointers as return types
for factory functions that create the resources, not raw pointers. Even
worse, this proposal means that the most convenient (since shortest) way
to create a <code>unique_ptr<T></code> from arguments of <code>T</code> is not</p>
<blockquote><pre>
return make_unique<T>(args);
</pre></blockquote>
<p>
but rather</p>
<blockquote><pre>
return {new T{args}};
</pre></blockquote>
<p>
The Finnish experts pull no punches when they say such a thing is the
wrong evolution path to take. They have voiced vocal astonishment to
the proposed core language change just to support use cases that should
be or at the very least should become rare and legacy, especially when
that change breaks design expectations of tons of libraries.
</p>
<a name="Illogical"</a><h2>Choosing braces to mean "non-explicit" is illogical</h2>
<p>
Returning a braced-list has a meaning today. Consider:</p>
<blockquote><pre>
char f() {int x = 0; return {x};} // error: narrowing conversion of 'x' from 'int' to 'char' inside { }
</pre></blockquote>
<p>People learn that in order to avoid potentially-corrupting narrowing
conversions between built-in types, they can use braces. It seems very
illogical that for library types with explicit conversions, braces
suddenly bypass similar checking for potentially-corrupting cases!</p>
<a name="Breakage"></a><h2>Breaking existing code</h2>
<p>The proposal does break existing code:</p>
<p>
<pre>
<code>
#include <iostream>
struct A {
explicit operator int() const {
std::cout << "meow" << std::endl; return 0;
}
operator short() const {
std::cout << "wuff" << std::endl; return 0;
}
};
int f()
{
A a;
return {a};
}
int main()
{
f();
}
</code>
</pre>
</p>
<p>This code currently prints "wuff". With the proposal, it would print
"meow". Is that a significant problem? We don't know.
</p>
<a name="RemainingRepeatsOfReturnType"></a><h2>Are there still cases where the return type must be repeated anyway?</h2>
<p>Consider the following code:</p>
<p>
<pre>
<code>
struct B {};
struct A {
operator B() const {return B{};}
};
B f()
{
A a;
return {a}; // clang and gcc reject
//return B{a}; // clang and gcc still reject
//return B(a); // clang and gcc accept
//return a; // clang and gcc accept
}
int main()
{
f();
}
</code>
</pre>
</p>
<p>It would seem that a return of a braced-init-list would not work
for such code. Does the proposal cover such cases, too?
</p>
<a name="Alternative"></a><h2>Alternative solutions</h2>
<p>There are a couple of ways to alleviate the burden of having
to repeat a return type that have already been suggested:</p>
<ul>
<li>just typedef the return type to something shorter for the definition of the function (not the first declaration, necessarily)</li>
<li>use a wrapper function, like wrap_unique<T> that wraps its argument
into a unique_ptr<T></li>
<li>use a domain-specific smart pointer type that has the desired semantics,
instead of changing the standard semantics</li>
<li>adopt a different syntactic way to express the intent desired, such
as <code>return explicit foo;</code></li>
</ul>
<a name="Summary"></a><h2>Summary</h2>
<p>
For us, these examples stress the point that when a type author writes
"<code>explicit</code>", we should never ignore it. Not on a <code>return</code>
statement. Not anywhere. The type author knows best. He had the option to
not make his conversion <code>explicit</code>, and he felt strongly enough
about the decision to <i>opt-in</i> to an <code>explicit</code> conversion.
</p>
<p>
We recall that when <code><chrono></code> was going through the
standardization process, the entire committee felt <i>very strongly</i> that
<code>int</code> should never implicitly convert to a <code>duration</code>.
</p>
<p>
If we want more conversions to be implicit, then we should not mark those
conversions with the <code>explicit</code> qualifier. This is a far superior
solution compared to marking a conversion explicit, and then treating the
conversion as implicit in a few places. And this is the direction of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3739.html">N3739</a>.
Instead of changing the rules for every type,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3739.html">N3739</a>
removes the <code>explicit</code> qualifier from specific types where it is
undesirable to have it, while keeping the <code>explicit</code> qualifier in
places that respect the type author's wishes.
</p>
<p>
All of the chrono, tuple and smart pointer examples are practical cases of a
general conceptual case: a conversion from a type with no semantics to a type
with strict semantics. Bypassing the explicitness of such conversions is
exceedingly dangerous, especially when it happens after-the-fact that the
designers of those library types chose to mark such conversions explicit.
The proposed change is moving the earth under the library designers' feet.
</p>
</body>
</html>