forked from HowardHinnant/papers
-
Notifications
You must be signed in to change notification settings - Fork 5
/
why_i_want_concepts.html
344 lines (320 loc) · 13.5 KB
/
why_i_want_concepts.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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Why I want Concepts, and why I want them sooner rather than later</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/>
Audience: WG21
<br/>
<br/>
<a href="mailto:[email protected]">Ville Voutilainen</a><br/>
2016-02-05<br/>
</address>
<hr/>
<h1 align=center>Why I want Concepts, and why I want them sooner rather than later</h1>
<h2>Abstract</h2>
<p>
This paper provides highly-opinionated statements, anecdotes and personal
opinions explaining why the author thinks Concepts should go into C++17
even if no Conceptified standard library parts are included in C++17.
</p>
<h2>Contents</h2>
<ul>
<li><a href="#InBrief">In brief</a></li>
<li><a href="#ConceptsAreSuperior">Concepts are superior to the work-around techniques we have to apply today</a></li>
<li><a href="#Deduction">Concepts allow constraining function arguments without turning off deduction and without disturbing arity</a></li>
<li><a href="#Overloading">Concepts make it much easier to write overloads with mutually exclusive constraints</a></li>
<li><a href="#BroadRange">Concepts enable a broad range of constraint designs</a></li>
<li><a href="#StdLib">So why shouldn't we ship Concepts and a Conceptified standard library at the same time?</a></li>
<li><a href="#LibAndDesign">But shouldn't the design of Concepts be validated by applying them to the library?</a></li>
<li><a href="#FamousLastWords">Famous last words</a></li>
</ul>
<a name="#InBrief"/><h2>In brief</h2>
<p>
Concepts are ready to go in; furthermore they provide important facilities
that are extremely burdensome and expert-only to mimic in C++14 and
below, and I want to be able to begin applying those facilities
in practice. I do not want to wait for a conceptified standard
library before being able to do so. I have analyzed the applicability
of Concepts in a limited fashion for the interfaces and the implementation
of the standard library, and I do not believe applying Concepts in
the standard library will result in design changes to Concepts.
</p>
<p>
Based on that confidence, I reiterate: it's time to ship Concepts
the language facility, and we should not wait for the standard library
to be partially or completely conceptified before doing so.
</p>
<a name="ConceptsAreSuperior"/><h2>Concepts are superior to the work-around techniques we have to apply today</h2>
<p>
There's a whole host of things Concepts make much more direct and convenient
to express than the work-arounds we use today. It's perhaps valuable
to look at some such cases with examples, which I will do in the subsequent
sections. Here's a teaser list:
</p>
<p>
<ul>
<li>
Concepts allow constraining function arguments without turning
off deduction and without disturbing the meta-arity of a constrained
function template.
</li>
<li>
Concepts make it much easier to write overloads with mutually
exclusive constraints.
</li>
<li>
Concepts enable a broad range of constraint designs, giving the
interface designer various tools to decide what sort of abstractions
a particular interface needs.
</li>
</ul>
</p>
<a name="Deduction"/><h2>Concepts allow constraining function arguments without turning off deduction and without disturbing arity</h2>
<p>
We start with something very simple:
</p>
<p>
<pre>
<code>
template <class T> void f(T);
</code>
</pre>
</p>
<p>
The problem here is that while this function template does deduction,
it provides no actual interface. If we want to constrain its function
parameter, we may initially try this:
</p>
<p>
<pre>
<code>
template <class T> void f(enable_if_t<my_trait_v<T>, T>);
</code>
</pre>
</p>
<p>
We just turned off deduction. That also means that the technique will
not work for constructor templates. We may try a different approach:
</p>
<p>
<pre>
<code>
template <class T> auto f(T) -> enable_if_t<my_trait_v<T>, void>;
</code>
</pre>
</p>
<p>
Now we have a constraint for the parameter in the return type. Same applies
to using a decltype of an expression in the trailing-return-type. This
won't work with constructor templates either. We can
resort to using constraints on the template argument:
</p>
<p>
<pre>
<code>
template <class T, typename = enable_if_t<my_trait_v<T>>> void f(T);
</code>
</pre>
</p>
<p>
Now we have changed the function template's meta-arity from one to two. All of
these solutions are work-arounds. With concepts, we can do
</p>
<p>
<pre>
<code>
void f(MyConcept);
</code>
</pre>
</p>
<p>
The constraint for the parameter is at the parameter. The function
template will still deduce the template argument. The arity of the
function template is unchanged, as is its meta-arity.
</p>
<a name="Overloading"/><h2>Concepts make it much easier to write overloads with mutually exclusive constraints</h2>
<p>
It's often desirable to constrain overloads of function templates
so that one overload is invoked when the template argument
satisfies certain criteria, and another overload if not. Let's look
at a thrilling example of what a person too clever for his own
good will write utilizing "nifty" techniques in C++14:
</p>
<p>
<pre>
<code>
template <class T> void f(T, decltype(declval<T>().f())* = 0);
</code>
</pre>
</p>
<p>
Pardon me. I should've warned you. The person is indeed too clever
for his own good, and he is very dangerous when given "nifty" facilities.
He didn't want to write a trait, because chances are that he's never
going to reuse the constraint on the function, and is thus unwilling
to separate it into a trait. So, he gets the declval of the template
parameter, constructs the expression, and turns its type into a pointer (and
completely fails to take into account references) because he wanted
to support functions returning void, and defaults the argument
in order to allow users to just call the function with one argument.
</p>
<p>
After all this, the "expression constraint" doesn't work with functions
that return references, the whole constraint can be accidentally bypassed
by invoking the function with two arguments, and no non-expert
will have any hope of ever understanding what's going on there. To add
insult to injury, this clever person can't figure out how to declare
the overload that is supposed to be taken when the constraint is not
satisfied. Any non-trait attempts he may make result in hard errors.
</p>
<p>
In contrast, with Concepts, here's what this too-clever programmer
will write:
</p>
<p>
<pre>
<code>
template <class T> void f(T) requires requires (T t) {t.f();};
template <class T> void f(T);
</code>
</pre>
</p>
<p>
The overloads are mutually exclusive, and everything is fine. If this
programmer so chooses, he can write an actual Concept for the constraint,
and apply separation of concerns that way. With the trait-based solutions,
the programmer
<b>has to write a trait</b>, for every expression he wants to
constrain on, because
otherwise he can't write the non-matching overload that requires
a negation of the trait. He will also potentially run into the
aforementioned problems with deduction, placement of the constraint,
or arity. Sure, a requires-clause is not exactly next to the parameter
either, but at least it's not hiding inside a trailing return type.
</p>
<a name="BroadRange"/><h2>Concepts enable a broad range of constraint designs</h2>
<p>
The previous section very much hinted towards the topic of this section.
For expression constraints, choosing an overload for which an expression
is not valid requires writing a trait. It can't be written in an
ad-hoc manner straight on the function template declaration. With
Concepts, that is possible, and the code design evaluation path towards
a real separate Concept is palatable, as is the evaluation path
back towards an ad-hoc constraint. None of the issues with the
C++14 techniques for constraints arise easily.
</p>
<p>
With Concepts, the programmer can decide what kind of an abstraction
level is suitable for his constraints, and it's possible to mix and
match Concepts and traits and requires-clauses fairly easily. None
of that design leeway is attainable with the C++14 techniques.
</p>
<a name="StdLib"/><h2>So why shouldn't we ship Concepts and a Conceptified standard library at the same time?</h2>
<p>
I don't want to wait for the conceptification of the standard library
before I can use the techniques illustrated in this paper (and there's
more than the examples in this paper). There's a lot of code that
can begin to benefit from those techniques even without a conceptified
library. In many cases, such code wouldn't benefit much or at all from
a conceptified library. Yes, I'm fully aware of the original goal
of Concepts being to create something that can reasonably be used
for the interfaces in the standard library; however, the language
facilities it ended up providing are so alluring that they in somecases
overshadow the benefits of some day having a constrained standard library.
</p>
<p>
I can start applying some of these techniques in some modern codebases
now, in some modern codebases as soon as GCC 6 is out, and in some
codebases when there's more than one compiler supporting Concepts.
We currently have basic library Concepts in the Ranges TS, and any
further conceptified library will likely just begin to form after we
have gotten that TS to the publication phase. From that point, it
takes some serious effort and time to further conceptify our standard
library. It's not unreasonable to expect this process to take a couple
of years, and all the while there would be a vast amount of code that
could immensely benefit from Concepts the language feature.
</p>
<a name="LibAndDesign"/><h2>But shouldn't the design of Concepts be validated by applying them to the library?</h2>
<p>
Some audiences think we cannot be sure that we got the design of
Concepts right before we apply Concepts to the standard library.
Furthermore, to some audiences this means just applying them
into the specification in a somewhat abstract sense, and to some
it means that Concepts need to be applied to the implementation as
well. Even further, some audiences think Concepts should be applied
to both the standard interfaces and the internal facilities of
a library implementation. The claim is that such an exercise
is bound to reveal bugs in the Concepts design.
</p>
<p>
Let's go from bottom to top for those concerns:
</p>
<p>
The applicability of Concepts to the internal facilities
and the standard interfaces of a library implementation has
been explored in a limited fashion. I have implemented
certain internal facilities with fake Concepts, and tried out the
techniques with actual Concepts. I didn't find any significant
design changes I would want to have for Concepts. Extension ideas,
yes; but such extensions are not really in scope for Concepts
at this time - the extension ideas were mostly for ways to
make implementing the guts of the library easier, and Concepts
weren't designed for that; they were designed to be able to
constrain the interfaces of the library, not for constraining
the implementation.</p>
<p>There's been somewhat limited amounts of field experience with
even the main use case of Concepts, constraining library interfaces.
Even so, we have had some feedback from adventurous library writers,
and thus far there have been fairly minor gripes about the Concepts
design. They have been mostly requests to simplify Concepts (at
the cost of decreased functionality, which was one of the reasons why
those design issues were rejected by EWG) and requests to relax
some limitations (which has been done to a certain extent). No
really major design issues have been reported by anyone. That
can certainly be an indication of small amounts of field experience,
but I daresay that it's an indication that the design is sound.
</p>
<p>We have had some amounts of specification experience with
libraries, such as the Ranges TS. As far as I know, no major
design issues for Concepts have come up. I very much doubt
applying Concepts to more library facilities would reveal
such issues, because I boldly claim that such issues aren't there.
</p>
<a name="FamousLastWords"/><h2>Famous last words</h2>
<p>
I realize that the previous section might not be convincing to some
people, and that shipping Concepts the language feature is a leap of
faith. That may well be so, but programmers are aching to get
the language feature into their hands, and it's high time
we ship it to them. Conceptifying the standard library will
take its time, and we will not find major design issues for Concepts
while doing it. We shouldn't keep programmers waiting for the
language feature out of concern for hypothetical design issues
that we have no proof of, have some amounts of counter-proof of, and
very likely don't exist.
</p>
<p>
For the benefit of C++ users everywhere, let's ship Concepts the
language feature in C++17.
</p>
</body>
</html>