forked from PhilippeSigaud/D-templates-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplates_appendix.tex
362 lines (278 loc) · 19.2 KB
/
templates_appendix.tex
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
\newpage
\part*{Appendices}
\addcontentsline{toc}{part}{Appendices}
\appendix
\section{
\texorpdfstring{A Crash Course on the \D{is}\DD{(...)} Expression}
{A Crash Course on the is(...) expression}}
\label{isexpression}
\subsection{General Syntax} \label{issyntax}
The \D{is}\DD{(...)} expression gives you some compile-time introspection\index{compile-time!introspection} on types (and, as a side-effect, on D expressions). It's described \href{http://www.dlang.org/expression.html#IsExpression}{here} in the D website. This expression has a quirky syntax, but the basic use is very simple and it's quite useful in conjunction with \D{static if} (see section \ref{staticif}) and template constraints (see section \ref{constraints}). The common syntaxes are:
\index{syntax!is expression@\D{is} expression}
\begin{dcode}
is( Type (optional identifier) )
is( Type (optional identifier) : OtherType,
(optional template parameters list) )
is( Type (optional identifier) == OtherType,
(optional template parameters list) )
\end{dcode}
If what's inside the parenthesis is valid (see below), \D{is}\DD{()} returns \D{true} at compile-time, else it returns \D{false}.
\subsection{\texorpdfstring{\D{is}\DD{(Type)}}
{is(Type)}}
\label{istype}
Let's begin with the very first syntax: if \DD{Type} is a valid D type in the scope\index{scope!local scope} of the \D{is} expression, \D{is}\DD{()} returns \D{true}. As a bonus, inside a \D{static if}, the optional \DD{identifier} becomes an alias for the type. For example:
\index{is expression@\D{is} expression}
\begin{dcode}
module canbeinstantiated;
template CanBeInstantiatedWith(alias templateName, Types...)
{
// is templateName!(Types) a valid type?
static if (is( templateName!(Types) ResultType ))
// here you can use ResultType (== templateName!(Types))
alias ResultType CanBeInstantiatedWith;
else
alias void CanBeInstantiatedWith;
}
\end{dcode}
Note that the previous code was done with templates in mind, but it is quite robust: if you pass as \DD{templateName} something that's not a template name (a func\-tion name, for ex\-am\-ple), the \D{is} will see \DD{templateName!(Types)} has no valid type and will return \D{false}. \DD{CanBeInstantiatedWith} will cor\-rec\-tly be set to \D{void} and your program does not crash.
\aparte{Testing for an alias}{Sometimes you do not know if the template argument you received is a type or an alias (for example, when dealing with tuples elements). In that case, you can use \DD{!}\D{is}\DD{(symbol)} as a test. If it really is an alias and not a type, this will return \D{true}.}
An interesting use for this form of \D{is}, is testing whether or not some D code is valid. Consider: D blocks are seen as delegates by the compiler (Their type is \D{void delegate}\DD{()}). Using this in conjunction with \D{typeof} let you test the validity of a block statement: if \DD{some code} is valid, \D{typeof}\DD{(\{ some code \}())} (note the \DD{()} at the end of the delegate to 'activate' it) has a real D type and \D{is} will return true.
Let's put this to some use. Imagine you have a function template \DD{fun} and some arguments, but you do not know if \DD{fun} can be called with this particular bunch of arguments. If it's a common case in your code, you should abstract it as a template. Let's call it \DD{validCall} and make it a function template also, to easily use it with the arguments:
\index{is(typeof())@\D{is}\DD{(}\D{typeof}\DD{())}}
\begin{dcode}
module validcall;
import std.conv;
bool validCall(alias fun, Args...)(Args args)
{
static if (is( typeof({ /* code to test */
fun(args);
/* end of code to test */
}())))
return true;
else
return false;
}
// Usage:
T add(T)(T a, T b) { return a+b;}
string conc(A,B)(A a, B b) { return to!string(a) ~ to!string(b);}
void main()
{
assert( validCall!add(1, 2)); // generates add!(int)
assert(!validCall!add(1, "abc")); // no template instantiation possible
assert( validCall!conc(1, "abc")); // conc!(int, string) is OK.
assert(!validCall!conc(1) ); // no 1-argument version for conc
struct S {}
assert(!validCall!S(1, 2.3)); // S is not callable
}
\end{dcode}
Note that the tested code is simply `\DD{fun(args);}'. That is, there is no condition on \DD{fun}'s type: it could be a function, a delegate or even a struct or class with \D{opCall} defined. There are basically two ways \DD{fun(args);} can be invalid code: either \DD{fun} is not callable as a function, or it is callable, but \DD{args} are not valid arguments.
By the way, fun as it may be to use this trick, D provides you with a cleaner way to test for valid compilation:
\begin{dcode}
__traits(compiles, { /* some code */ })
\end{dcode}
\D{\_\_traits} is another of D numerous Swiss Army knife constructs. You can find the \DD{compiles} documentation \href{http://www.dlang.org/traits.html#compiles}{here}. Section \ref{traits} is dedicated to it.
\subsection{
\texorpdfstring{\D{is}\DD{(Type : AnotherType)} and \D{is}\DD{(Type == AnotherType)}}
{is(Type : AnotherType) and is(Type == AnotherType)}}
\label{istypeanothertype}
The two other basic forms of \D{is} return true if \DD{Type} can be implicitly converted to (is derived from) \DD{AnotherType} and if \DD{Type} is exactly \DD{AnotherType}, respectively. I find them most interesting in their more complex form, with a list of template parameters afterwards. In this case, the template parameters act a bit as type variables in an equation. Let me explain:
\index{syntax!is expression@\D{is} expression}
\begin{dcode}
is(Type identifier == SomeComplexTypeDependingOnUAndV, U, V)
\end{dcode}
really means: `excuse me, Mr. D Compiler, but is \DD{Type} perchance some complex type depending on \DD{U} and \DD{V} for some \DD{U} and \DD{V}? If yes, please give me those.'
For
\index{is expression@\D{is} expression}
\begin{dcode}
template ArrayElement(T)
{
// is T an array of U, for some U?
static if (is(T t : U[], U))
alias U ArrayElement; // U can be used, let's expose it
else
alias void ArrayElement;
}
template isAssociativeArray(AA)
{
static if (is( AA aa == Value[Key], Value, Key))
/* code here can use Value and Key,
they have been deduced by the compiler. */
else
/* AA is not an associative array
Value and Key are not defined. */
}
\end{dcode}
Strangely, you can only use it with the \D{is}\DD{(Type identifier, ...)} syntax: you \emph{must} have \DD{identifier}. The good new is, the complex types being inspected can be templated types and the parameter list can be any template parameter: not only types, but integral values, \ldots.
For example, suppose you do what everybody does when encountering D templates: you create a templated n-dimensional vector type.
\begin{dcode}
struct Vector(Type, int dim) { ... }
\end{dcode}
If you did not expose \DD{Type} and \DD{dim} (as aliases for example, as seen in sections \ref{inneralias} and \ref{givingaccess}), you can use \D{is} to extract them for you:
\begin{dcode}
Vector!( ?, ?) myVec;
// is myVec a vector of ints, of any dimension?
static if (is(typeof(myVec) mv == Vector!(int, dim), dim))
// is it a 1-dimensional vector?
static if (is(typeof(myVec) mv == Vector!(T, 1), T))
\end{dcode}
\aparte{is( A != B)?}{No, sorry, this doesn't exist. Use \DD{!}\D{is}\DD{(A == B)}. But beware this will also fire if \DD{A} or \DD{B} are not legal types (which makes sense: if \DD{A} is not defined, then by definition it cannot be equal to \DD{B}). If necessary, you can use \D{is}\DD{(A) \&\& }\D{is}\DD{(B) \&\& !}\D{is}\DD{(A == B)}.}
\aparte{is A a supertype to B?}{ Hey, \D{is}\DD{(MyType : SuperType)} is good to know if \DD{MyType} is a subtype to \DD{SuperType}. How do I ask if \DD{MyType} is a supertype to \DD{SubType}? Easy, just use \D{is}\DD{(SubType : MyType)}.}
For me, the main limitation\index{is expression@\D{is} expression!limitation} is that template tuple parameters are not accepted. Too bad. See, imagine you use \stdanchor{typecons}{Tuple} a lot. At one point, you need a template to test if something is a \DD{Tuple!(T...)} for some \DD{T} which can be 0 or more types. Though luck, \D{is} is a bit of a letdown there, as you cannot do:
\begin{dcode}
template isTuple(T)
{
static if (is(T tup == Tuple!(InnerTypes), InnerTypes...)
(...) ^^^^^^^^^^^^^
\end{dcode}
But sometimes D channels its inner perl\index{perl!inner perl in D} and, lo! There is more than one way to do it! You can use IFTI\index{IFTI} (see \ref{ifti}) and our good friend the \D{is}\DD{(}\D{typeof}\DD{({...}()))} expression there. You can also use \D{\_\_traits}, depending on you mood, but since this appendix is specifically on \D{is}:
\index{is(typeof())@\D{is}\DD{(}\D{typeof}\DD{())}}
\begin{ndcode}
module istuple;
import std.typecons;
template isTuple(T)
{
static if (is(typeof({
void tupleTester(InnerTypes...)(Tuple!(InnerTypes) tup) {}
T.init possibleTuple;
tupleTester(possibleTuple);
}())))
enum bool isTuple = true;
else
enum bool isTuple = false;
}
\end{ndcode}
Line 7 defines the function template \DD{tupleTester}, that only accepts \DD{Tuple}s as arguments (even though it does nothing with them). We create something of type \DD{T} on line 8, using the \DD{.init} property inherent in all D types, and try to call \DD{tupleTester} with it. If \DD{T} is indeed a \DD{Tuple} this entire block statement is valid, the resulting delegate call indeed has a type and \D{is} returns \D{true}.
There are two things to note here: first, \DD{isTuple} works for any templated type called \DD{Tuple}, not only \stdanchor{typecons}{Tuple}. If you want to restrict it, change \DD{tupleTester} definition. Secondly, we do not get access to the inner types this way. For \stdanchor{typecons}{Tuple} it's not really a problem, as they can be accessed with the \DD{someTuple.Types} alias, but still\ldots
By the way, the template parameter list elements can themselves use the \DD{A : B} or \DD{A == B} syntax:
\begin{dcode}
static if (is( T t == A!(U,V), U : SomeClass!W, V == int[n], W, int n))
\end{dcode}
This will be OK if \DD{T} is indeed an \DD{A} instantiated with an \DD{U} and a \DD{V}, themselves verifying that this \DD{U} is derived from \DD{SomeClass!W} for some \DD{W} type and that \DD{V} is a static array of \D{int}s of length \DD{n} to be determined (and possibly used afterwards). In the if branch of the \D{static if} \DD{U}, \DD{V}, \DD{W} and \DD{n} are all defined.
\subsection{Type Specializations}\label{typespecializations}
There is a last thing to know about \D{is}: with the \D{is}\DD{(Type (identifier) == Something)} version, \DD{Something} can also be a type specialization\index{is expression@\D{is} expression!type specialization}, one of the following D keywords: \D{function}, \D{delegate}, \D{return}, \D{struct}, \D{enum}, \D{union}, \D{class}, \D{interface}, \D{super}, \D{const}, \D{immutable} or \D{shared}. The condition is satisfied if \DD{Type} is one of those (except for \D{super} and \D{return}, see below). \DD{identifier} then becomes an alias for some property of \DD{Type}, as described in table \ref{table:typespecializations}.
\begin{table}[htb]
\begin{adjustwidth}{-0.2cm}{} % long table: reducing left margin
\begin{tabular}[c]{cp{9em}p{17em}}
\hline
\multicolumn{1}{c}{Specialization} & \multicolumn{1}{c}{Satisfied if} & \multicolumn{1}{c}{\DD{identifier} becomes} \\ \hline% \hline
\D{function}& \DD{Type} is a function & The function parameters type tuple \\ %\hline
\D{delegate}& \DD{Type} is a delegate & The delegate function type \\ %\hline
\D{return}& \DD{Type} is a function & The return type \\
& \DD{Type} is a delegate & \\ \hline %\hline
\D{struct}& \DD{Type} is a struct & The struct type\\ %\hline
\D{enum}& \DD{Type} is an enum & The enum base type\\ %\hline
\D{union}& \DD{Type} is an union& The union type\\ %\hline
\D{class}& \DD{Type} is a class& The class type\\ %\hline
\D{interface}& \DD{Type} is an interface & The interface type\\ %\hline
\D{super}& \DD{Type} is a class& The type tuple (Base Class, Inter\-fa\-ces)\\ \hline %\hline
\D{const}& \DD{Type} is const & The type\\ %\hline
\D{immutable}& \DD{Type} is immutable & The type\\ %\hline
\D{shared}& \DD{Type} is shared & The type\\ \hline
\end{tabular}
\caption{Effect of type specializations in \D{is}}
\label{table:typespecializations}
\end{adjustwidth}
\end{table}
Let's put that to some use: we want a factory template that will create a new struct or a new class, given its name as a template parameter:
\index{is expression@\D{is} expression!type specialization}
\begin{dcode}
module maker;
import std.algorithm;
import std.conv;
template make(A)
if (is(A a == class )
|| is(A a == struct))
{
auto make(Args...)(Args args)
{
static if (is(A a == class))
return new A(args);
else
return A(args);
}
}
struct S {int i;}
class C
{
int i;
this(int ii) { i = ii;}
override string toString() @property { return "C("~to!string(i)~")";}
}
void main()
{
auto array = [0,1,2,3];
auto structRange = map!( make!S )(array);
auto classRange = map!( make!C )(array);
assert(equal(structRange, [S(0), S(1), S(2), S(3)]));
assert(classRange.front.toString == "C(0)");
}
\end{dcode}
You can find another example of this kind of \D{is} in section \ref{classtemplates}, with the \DD{duplicator} template.
\section{Resources and Further Reading}
\label{resources}
\unfinished{Any new resource welcome!}
Being a relatively young language, D doesn't have dozens of books or online sites dedicated to its learning. Still, there are a few resources on the Internet that pertains to D templates and associated subjects.
\subsection{D Templates}
Here are some resources on D templates.
\subsubsection{D Reference}
\label{dreference}
Your first stop should be the \href{http://dlang.org}{dlang.org} pages on templates. They are quite easy to read, don't hesitate to peruse them and bother the authors if anything is unclear or blatantly false. The \DD{dlang.org} website is also a github project, \href{https://github.com/D-Programming-Language/d-programming-language.org}{here}. Table \ref{table:dlangpages} lists the pages dealing with templates.
\begin{table}[htb]
\begin{adjustwidth}{-1.3cm}{} % long table: reducing left margin
\begin{tabular}[l]{p{14em}l}
\hline
\multicolumn{1}{c}{Subject} & \multicolumn{1}{c}{URL}\\ \hline %\hline
The general page on templates & \url{http://dlang.org/template.html}\\ %\hline
D templates vs C++ ones & \url{http://dlang.org/templates-revisited.html} \\ %\hline
An article on tuples & \url{http://dlang.org/tuple.html}\\ %\hline
Template tuple parameters & \url{http://dlang.org/variadic-function-templates.html} \\ %\hline
Template constraints & \url{http://dlang.org/concepts.html}\\ %\hline
Mixin Templates & \url{http://dlang.org/template-mixin.html}\\ %\hline
A small article on string mixins & \url{http://dlang.org/mixin.html}\\% \hline
\D{static if} & \url{http://dlang.org/version.html#staticif}\\ %\hline
\D{is} & \url{http://dlang.org/expression.html#IsExpression}\\ %\hline
Type Aliasing & \url{http://dlang.org/declaration.html#alias}\\ %\hline
Operator Overloading & \url{http://dlang.org/operatoroverloading.html}\\ \hline
\end{tabular}
\caption{\url{dlang.org} pages dealing with templates}
\label{table:dlangpages}
\end{adjustwidth}
\end{table}
\subsubsection{The D Programming Language}
\label{TDPL}
The main D book as of this writing is of course \textsc{The D Programming Language} (also known as \textsc{TDPL}), by Andrei Alexandrescu. It's a very good reference book, and fun to read too. TDPL has a very interesting approach to templates: Andrei first introduces them as a natural extension of functions, classes, and structs syntax, to get parametrized code. It's only afterwards that templates-as-scopes are introduced. Table \ref{table:tdplchapters} lists the chapters that deals with templates.
\begin{table}[htb]
\centering
\begin{tabular}[c]{ll}
\hline
\multicolumn{1}{c}{Subject} & \multicolumn{1}{c}{Chapter} \\ \hline
Functions Templates & 5.3, 5.4, 5.10, and 5.12\\
Classes Templates & 6.14 \\
Struct Templates & 7.1.10 \\
\D{alias} & 7.4 \\
General Templates & 7.5 \\
Mixin Templates & 7.6 \\
Operator Overlaoding & 12 \\ \hline
\end{tabular}
\caption{TDPL Chapters Dealing With Templates}
\label{table:tdplchapters}
\end{table}
\subsubsection{Programming in D}
\label{programmingind}
Another quite interesting book is the translation from Turkish of Ali \c{C}ehreli's book \textsc{Programming in D}, which you can find for free here: \url{http://ddili.org/ders/d.en/index.html}. More precisely, as far as this document is concerned, the chapter on templates is already translated and can be found at \url{http://ddili.org/ders/d.en/templates.html}. Ali's book aims to be a gentle introduction to D, so the rhythm is less gung ho than TDPL. If you do not want to read the present document,\footnote{ It's probably too late. Should I link to Ali's book earlier?} the previously linked chapter is your best bet as a template tutorial.
\subsubsection{The D Wiki}
\label{dwiki}
Apart from books, the D wiki has a tutorial on templates that can be found at \url{http://prowiki.org/wiki4d/wiki.cgi?D__Tutorial/D2Templates}, that explains \stdanchor{functional}{unaryFun} very thoroughly, dealing in passing with various subjects such as templates, string mixins, and instantiation scope. I found it a very pleasant read and a nice explanation of a difficult part of Phobos.
\subsection{D Metaprogramming}
\label{dmetaprogramming}
I found Nick Sabalausky's article at \url{http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/} to be a very good read, and full of nifty ideas. In particular, Nick shows how to use compile-time information to craft code such that runtime arguments can then be used to ``influence'' compile-time values. Yes you read that right, and my description does not do it justice: \href{http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/#part6-3}{read on}, and see for yourselves. I definitely \emph{must} put a section somewhere in this doc on this.
The code shown in the article can be found in a github project, at \url{https://github.com/Abscissa/efficientAndFlexible}
\subsection{Templates in Other Languages}
\label{templatesinotherlanguages}
\unfinished{C++ templates, obviously. Articles, online books, and such. A small text on Boost. Also, maybe Java and C\# generics.}
\subsection{Genericity in Other Languages}
\label{genericity}
\unfinished{Haskell and ML concerning types. In general, any type trick that Haskellers live by: encoding information in types, using types to forbid unwanted states and so on.}
\subsection{Metaprogramming in Other Languages}
\subsection{macros}
\unfinished{Maybe Lisp / Scheme / Clojure macros. Nemerle macros too.}