forked from PhilippeSigaud/D-templates-tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplates_advanced.tex
1934 lines (1464 loc) · 79.3 KB
/
templates_advanced.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
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
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\newpage
\part{Some More Advanced Considerations}\label{advanced} %%%%%%%%%%%%%%%
In the previous part, we saw what everyone should know about D templates. But in fact, there is much more to them than that. What follows is not necessarily more complicated, but it's probably a little less commonly used. As this document matures, some subjects may flow from \autoref{basics} into \autoref{advanced} and the other way round.
\section{Constraints}\label{constraints}
Templates constraints\index{template!constraints} are a way to block a template instantiation if some condition is not met. Any condition that can be determined at compile-time is authorized, which makes constraints a superset of templates specializations\index{template!specialization} (see \ref{specializations}). As such, their usage grew rapidly once they were introduced and, if Phobos\index{Phobos} is any indication, templates specializations are on the contrary becoming less common.
\subsection{Syntax}\label{constraintssyntax}
To obtain a constraint, put an \D{if} clause just after the template parameter list, and before the enclosed scope\index{scope!constraint}:
\index{syntax!templates constraints}
\begin{dcode}
template templateName(T,U,V) if (someCondition on T, U or V)
{
...
}
\end{dcode}
When the compiler tries to instantiate a template, if will first check the constraint. If it evaluates to \D{false}, the template declaration is not part of the considered set. That way, using constraints, you can keep or drop templates at your leasure. \D{is} expressions\index{is expression@\D{is} expression} are your friend there, allowing you to get compile-time introspection\index{compile-time!introspection} on types. See the appendix (\ref{isexpression}) for a crash course on it.
You may have many template declarations with the same name and differing constraints (in fact, that's the very use case for constraints). Depending on the activated constraints, some or all will be considered by the compiler.
\index{template!constraints}
\begin{dcode}
module constrained;
template Constrained(T)
if (is(T : int)) { /*...*/ } // #1
template Constrained(T)
if (is(T : string)) { /*...*/ } // #2
template Constrained(T,U)
if (is(T : int) && !is(U : float)) { /*...*/ } // #3
template Constrained(T,U)
if (is(T : int) && is(U : float)) { /*...*/ } // #4
alias Constrained!(int) C1; // #1
// alias Constrained!(string) C2; // Error, no declaration fits (string)
alias Constrained!(int,string) C3;// #3 and #4 considered, but #4 is dropped.
// So #3 it is.
\end{dcode}
This syntax is the same for the special-cases templates seen in sections \ref{functiontemplates}, \ref{structtemplates}, \ref{classtemplates} and \ref{othertemplates}. The only tricky part is for class templates, where you may wonder where to put the constraint: before or after the inheritance list? The answer is: before.
\index{syntax!template constraints!for class templates}
\begin{dcode}
module constraintsyntax;
T theFunction(T)(T argument)
if (is(T : int) || is(T : double))
{ return argument; }
struct TheStruct(T)
if (is(T : int) || is(T : double))
{ /*...*/ }
class TheClass(T)
if (is(T : int) || is(T : double))
: BaseClass!T, Interface1
{ /*...*/ }
\end{dcode}
When you write constraints, just remember they are a compile-time construct. For \DD{theFunction}, \DD{argument} is not known at compile-time, only its type, \DD{T}. Do not use \DD{argument} in your constraint. If you need a value of type \DD{T}, use \DD{T.init}. For example:
\index{template!constraints}
\begin{dcode}
module ctvalue;
auto callTwice(alias fun, T)(T arg)
// Is it OK to do fun(fun(some T))?
if (is(typeof({
fun(fun(T.init));
}())))
{
return fun(fun(arg));
}
\end{dcode}
\subsection{Constraints Usage}\label{constraintsusage}
Constraints come from the same idea than C++0x\index{C++!C++0x} \DD{concept}, er\ldots, concept, although simpler to define, understand and, as shown by D, implement. The idea is to define a set of conditions a type must respect to be a representative of a `concept', and check for it before instantiating.
Have a look at constraints poster-child: \emph{ranges}\index{range}.\footnote{ Ranges are overdue a tutorial.} They were rapidly described in section \ref{functionflatten}.
\std{range} defines a set of templates\index{predicate templates!for ranges} that check the different ranges concepts, called \DD{isInputRange}, \DD{isForwardRange}\ldots I call these \D{bool}-becoming templates \emph{predicate templates} and talk about them in section \ref{predicates}. Usage is quite simple:
\index{predicate templates}
\index{range templates}
\begin{dcode}
module rangewrapper;
import std.range;
struct RangeWrapper(Range)
// Does Range comply with the input range 'concept'?
if (isInputRange!Range)
{
/* Here we know that Range has at least three member functions:
.front(), .popFront() and .empty(). We can use them happily.*/
}
// In the factory function too.
auto rangeWrapper(Range)(Range range) if (isInputRange!Range)
{
return RangeWrapper!(Range)(range);
}
\end{dcode}
In fact, it's a bit like a sort of compile-time interface or compile-time duck-typing: we do \emph{not} care about \DD{Range}'s `kind': it may by a \D{struct} or a \D{class} for all we know. What is important is that it respects the \emph{input range} concept.
The good news is that the compiler will complain\footnote{ I think \emph{compiler} and \emph{complain} must have the same root.} when it cannot instantiate a template due to constraints being not respected. It gives better error messages this way (although not as good as you might need).
\subsection{Constraints Limits}\label{constraintslimits}
The main problem is that, compared to templates specializations, you cannot do:
\index{template!constraints!limitations}
\begin{dcode}
module constraints_error;
template Temp(T)
if (is(T:int)) // #1, specialized for ints
{ /*...*/ }
template Temp(T) // #2, generic case
{ /*...*/ }
alias Temp!int TI;// Error!
\end{dcode}
Why an error? Because the compiler finds that both the \D{int}-specialized and the generic version can be instantiated. It cannot decide which one you mean and, quite correctly, does nothing, humble code that it is. No problem, says you, we will just add a constraint to the generic version:
\begin{dcode}
template Temp(T) if (is(T:int)) // #1
{ ... } // specialized for ints
template Temp(T) if (!is(T:int))// #2
{ ... } // generic case
Temp!int // Works!
\end{dcode}
Now, when you try to instantiate with an \D{int}, template \#2 is not present (its constraint is false and was dropped from the considered template list) and we can have \#1. Hurrah? Not quite. The \#1-constraint wormed its way into the generic version, adding code where none was initially. Imagine you had not one, but three different specialized versions:
\begin{dcode}
template Temp(T) if (is(T:int[])) // #1a
{ ... } // specialized for arrays of ints
template Temp(T) if (isRange!T) // #1b
{ ... } // specialized for ranges
template Temp(T) if (is(T:double[n], int n)) // #1c
{ ... } // specialized for static arrays of double
template Temp(T) // #2, generic
if ( /* What constraint? */
{ ... }
\end{dcode}
OK, quick: what constraint for \#2? The complement to \emph{all} other constraints. See:
\begin{dcode}
template Temp(T) // #2, generic
if ( !(is(T:int[]))
&& !isRange!T
&& !is(T:double[n], int n))
{ ... }
\end{dcode}
That's becoming complicated to maintain. If someone else adds a fourth specialization, you need to add a fourth inverted version of its constraint. Too bad, you still compile and calls \DD{Temp}: \DD{Temp!(}\D{int}\DD{[])}. And there: error! Why? Because constraints \#1a and \#1b are not mutually exclusive: an \D{int}\DD{[]} is also a input range. Which means that for \#1b, you need to add a clause excluding arrays of \D{int} and maybe modify constraint \#2.
Ouch.
So, yes, constraints are wonderful, but they do have drawbacks. As a data point, this author uses them all the time, even though specializations (\ref{specializations}) are sometimes more user-friendly: most of what I want to impose and check on my types cannot be done by specializations.
\subsection{Constraints, Specializations and \D{static if}:}
\label{constraintsorspecializations}
I mean, come on! Three different ways to decide if your template exists or not?
\begin{dcode}
template Specialized(T : U[], U)
{ ... }
template Constrained(T) if (is(T : U[], U))
{ ... }
template StaticIfied(T)
{
static if (is(T : U[], U))
{ ... }
else // stop compilation
static assert(0, "StaticIfied cannot be instantiated.");
}
\end{dcode}
What were the D designers thinking? Well, they got specializations (\ref{specializations}) from D's cousin, C++\index{C++}. The two other subsystems were added a few years later, as the power of D compile-time metaprogramming\index{compile-time!introspection} became apparent and more powerful tools were needed. So, the 'modern' subsystems are constraints and \D{static if} (\ref{staticif})\index{static if@\D{static if}}. Constraints are much more powerful than specializations, as anything you can test with specialization, you can test with an \D{is} expression in a constraint\index{is expression@\D{is} expression!in a constraint}. And \D{static if} is wonderfully useful outside of template instantiation, so these two are well implanted in D and are there to stay.
What about specializations, now? First, they are quite nice to have when porting some C++\index{C++} code. Second, they have a nice effet that constraints do \emph{not} have: when more than one definition could be instantiated, priority is given to the more specialized. You saw the explanation in the previous subsection.
So in the end, the conclusion is a bit of \emph{D Zen}\index{D Zen}: you are given tools, powerful tools. As these are powerful, they sometimes can do what other options in your toolbox can do also. D does not constrain (!) you, chose wisely.
\section{Predicate Templates}\label{predicates}
When you find yourself typing again and again the same \D{is} expression\index{is expression@\D{is} expression} or the same complicated constraint\index{template!constraints}, it's time to abstract it into another template, a \D{bool}-becoming one.\index{predicate templates} If you have a look a section \ref{istype}, you'll see a way to test if a particular piece of D code is OK (compilable) or not. Another way to obtain this is by using \D{\_\_traits}\DD{(compiles, some Code)}\index{\_\_traits@\D{\_\_traits}}.
In \autoref{examples}, the section \ref{staticfilter}, on page \pageref{graphcheck} shows another example of a predicate template.
\subsection{Testing for a member}
For example, if you want to test is some type can be serialized, through a \D{size\_t}\DD{ serialize()} member function:
\index{predicate templates!member testing}
\begin{dcode}
module isserializable;
template isSerialazable(Type)
{
static if (__traits(compiles, {
Type type;
size_t num = type.serialize;
}))
enum bool isSerialazable = true;
else
enum bool isSerialazable = false;
}
\end{dcode}
\subsection{Testing for operations}
As seen in previous sections (\ref{structflatten}, \ref{constraintsusage}), we are writing here a kind of compile-time interface. Any type can pass this test, as long as it has a \DD{.serialize} member that returns a \D{size\_t}. Of course, you're not limited to testing member functions. Here is a template that verify some type has arithmetic operations:
\index{predicate templates!operator testing}
\begin{dcode}
module hasarithmeticoperations;
template hasArithmeticOperations(Type)
{
static if (__traits(compiles,
{
Type t, result;
result = t + t; // addition
result = t - t; // substraction
result = t * t; // multiplication
result = t / t; // division
result = +t; // unary +
result = -t; // unary -
}))
enum bool hasArithmeticOperations = true;
else
enum bool hasArithmeticOperations = false;
}
static assert(hasArithmeticOperations!int);
static assert(hasArithmeticOperations!double);
struct S {}
static assert(!hasArithmeticOperations!S);
\end{dcode}
As you can see, you can test for any type of D code, which means it's \emph{much} more powerful than templates specializations (\ref{specializations}\index{template!specialization!compared to constraints}) or the \D{is} expression (Appendix \ref{isexpression})\index{is expression@\D{is} expression!compared to constraints}.
You may also get a certain feel of a... \emph{pattern} emerging from the previous two examples. All the scaffolding, the boilerplate, is the same. And we could easily template it on what operator to test, for example. It's possible to do that, but it means crafting code at compile-time. Wait until you see string mixins\index{string mixins} (\ref{stringmixins}) and CTFE\index{CTFE} (\ref{ctfe}) in \autoref{around}.
\subsection{Completing the \DD{Flatten} range:}
Let's come back to \DD{Flatten} from section \ref{structflatten}. Using concept-checking templates, we will verify the range-ness of the wrapper type and promote \DD{Flatten} to forward range status if \DD{Range} itself is a forward range:
\index{predicate templates}
\index{range}
\begin{dcode}
import std.range;
struct Flatten(Range) if (isInputRange!Range)
{
/* same code than before */
static if (isForwardRange!Range)
Flatten save() @property
{
return this;
}
}
\end{dcode}
The struct is enriched in two ways: first, it cannot be instantiated on a non-range. That's good because with the code from section \ref{structflatten}, you could bypass the factory function and manually create a \DD{Flatten!}\D{int}, which wouldn't do. Now, you cannot. Secondly, if the wrapped range is a forward range, then \DD{Flatten!Range} is one also. That opens up whole new algorithms to \DD{Flatten}, for just a quite-readable little piece of code.
You could extend the pattern in the same way by allowing \DD{Flatten} to be a bidirectional range, but you would need to introduce a \DD{backSubRange} member that keeps trace of the range's back state.
\section{Template Tuple Parameters}\label{tuples}
\subsection{Definition and Basic Properties}\label{tupleproperties}
And now comes one of my favourite subjects: template tuple parameters\index{template!parameters!tuple}. As seen in section \ref{declarations} these are declared by putting a \DD{identifier...} at the last parameter of a template. The tuple will then absorb any type, alias or literal passed to it.
For this very reason (that it can bunch of types interspersed with symbols), some people consider it a mongrel addition to D templates. That is true, but the ease of use and the flexibility it gives us is in my opinion well worth the cost of a little cleanliness.
D template tuples have a \DD{.length} member (defined at compile-time, obviously), their elements can be accessed using the standard indexing syntax and they can even be sliced (the \DD{\$} symbol is aliased to the tuple length):
\index{template!tuple parameter}
\index{type tuple}
\begin{dcode}
module dropfront;
template DropFront(T...)
{
static if ( T.length > 0 // .length. At least 1 element
&& is(T[0] == int)) // Indexing
alias T[1..$] DropFront; // Slicing
else
alias void DropFront;
}
alias DropFront!(int, double, string) Shortened;
static assert(is( Shortened[0] == double));
static assert(is( Shortened[1] == string));
\end{dcode}
You can declare a value of type `tuple'. This value (called an expression tuple) also has a length, can be indexed and can be sliced. You can also pass it directly to a function if the types check with a function parameter list. If you throw it into an array\index{arrays!and expression tuples}, it will `melt' and initialize the array:
\index{expression tuple}
\index{tuple!expression tuple}
\begin{dcode}
module tupledemonstration;
template TupleDemonstration(T...)
{
alias T TupleDemonstration;
}
unittest
{
TupleDemonstration!(string, int, double) t;
assert(t.length == 3);
t[0] = "abc";
t[1] = 1;
t[2] = 3.14;
auto t2 = t[1..$];
assert(t2[0] == 1);
assert(t2[1] == 3.14);
void foo(int i, double d) {}
foo(t2); // OK.
double[] array = [t2]; // see, between [ and ]
assert(array == [1.0, 3.14]);
}
\end{dcode}
The simplest possible tuple is already defined in Phobos\index{Phobos} in \stdanchor{typetuple}{TypeTuple}:
\begin{dcode}
template TypeTuple(T...)
{
alias T TypeTuple; // It just exposes the T's
}
alias TypeTuple!(int, string, double) ISD;
static assert(is( TypeTuple!(ISD[0], ISD[1], ISD[2]) == ISD ));
\end{dcode}
Pure template parameter tuples are auto-flattening: they do \emph{not} nest:
\begin{dcode}
module ttflatten;
import std.typetuple;
alias TypeTuple!(int, string, double) ISD;
alias TypeTuple!(ISD, ISD) ISDISD;
// ISDISD is *not* ((int, string, double), (int, string, double))
// It's (int, string, double, int, string, double)
static assert(is(ISDISD == TypeTuple!(int,string,double,int,string,double)));
\end{dcode}
This is both a bug and a feature. On the negative side, that condemns us to linear structures: no trees of type tuples. And since a branching structure can give rise to a linear, that would have been strictly more powerful. On the positive side, that allow us to concatenate tuples easily (and from that, to iterate easily), as you'll see in sections \ref{variadicfunctions} and \ref{inheritancelist}. If you need recursive/branching structures, you can have them by using \stdanchor{typecons}{Tuple} or really any kind of struct/class template: the types are not flattened there. See for example section \ref{polymorphictree} for a fully polymorphic tree.
The last property tuples have is that they can be iterated over: use a \D{foreach} expression, like you would for an array. With \D{foreach}, you can iterate on both type tuples and expression tuples. The indexed version is also possible, but you cannot ask directly for a \D{ref} access to the values (but see the example below). This iteration is done at compile-time and is in fact one of the main ways to get looping at compile-time\index{compile-time!looping} in D.
\begin{dcode}
module ttiteration;
import std.typetuple;
unittest
{
alias TypeTuple!(string, int, double) T;
T t;
t[0] = "abc";
t[1] = 1;
t[2] = 3.14;
string[T.length] s;
foreach(index, Type; T) // Iteration on types.
// Type is a different, er, type at each position
{
static if(is(Type == double))
s[index] = Type.stringof;
}
assert(s == ["", "", "double"]);
void bar(T)(ref T d) { T t; d = t;}
foreach(index, value; t) // Iteration on values.
// value has a different type at each position!
{
bar(t[index]); // use t[iindex], not 'value' to get a ref access
}
assert(t[0] == "");
assert(t[1] == 0);
import std.math;
assert(std.math.isnan(t[2]));
}
\end{dcode}
As values of this type can be created and named, they are \emph{almost} first-class. They have two limitations, however:
\begin{itemize}
\item There is no built-in syntax for declaring a tuple. In the previous example, calling \DD{T.stringof} returns the string \DD{"(}\D{string}\DD{,}\D{int}\DD{,}\D{double}\DD{)"}. But you cannot write \DD{(}\D{string}\DD{,}\D{int}\DD{,}\D{double}\DD{) myTuple;} directly. Paradoxically, if you have a (\D{string},\D{int},\D{double}) type tuple called \DD{T}, you \emph{can} do \DD{T myTuple;}.
\item These tuples cannot be returned from a function. You have to wrap them in a struct. That's what \stdanchor{typecons}{Tuple} offers.
\end{itemize}
\index{tuple!the many kinds of}
\aparte{tuple, Tuple, T... and .tupleof}{A common question from newcomers to D is the difference and definition between the different tuples found in the language and the standard library. I will try to explain:
\emph{Template tuple parameters} are internal to templates. They are declared with \DD{T...} at the last position in the parameter list. They group together a list of template parameters, be they types, values or alias. Two `subtypes' are commonly used:
\emph{Type tuples} are template tuple parameters that hold only types.
\emph{Expression tuples} are tuples that hold only expressions. They are what you get when you declare a variable of type `type tuple'.
\emph{Function parameter tuples.} You can get a function parameter type tuple from \stdanchor{traits}{ParameterTypeTuple}. It's exactly a type tuple as seen before. A value of this type can be declared and can be passed to a function with the same parameters.
\emph{The }\DD{.tupleof}\emph{ property} is a property of aggregate types: classes and structs. It returns an expression tuple containing the members's values.
\emph{Member names tuple} is a tuple of strings you get by using \D{\_\_traits}\DD{(members, SomeType)}. It contains all \DD{SomeType} members' names, as strings (including the methods, constructors, aliases and such).
\stdanchor{traits}{TypeTuple} is a pre-defined template in Phobos that's the simplest possible template holding a tuple. It's the common D way to deal with type tuples. The name is bit of a misnomer, because it's a standard template parameter tuple: it can hold types, but also values.
\stdanchor{typecons}{Tuple} and \stdanchor{typecons}{tuple} are pre-defined struct/function templates in Phobos\index{Phobos} that gives a simple syntax to manipulate tuples and return them from functions.
}
\subsection{The Type of Tuples}\label{typeoftuples}
You can get a tuple's type by using \D{typeof}\DD{(tuple)}, like any other D type. There are two limit cases:
\begin{description}
\item[One-element tuples:] There is a difference between a tuple of one element and a lone type. You cannot initialize a standard value with a 1-element tuple. You have to extract the first (and only) element before. In the same idea, the 1-element tuple has a length and can be sliced: actions that do not make sense for a standard type.
\item[Zero-element tuples:] It's possible to have an empty tuple\index{tuple!empty}, holding zero type, not to be confused with a uninitialized n-elements tuple or the tuple holding \D{void} as a type. In fact, the zero-element tuple can only have one value: its initialization value. For this reason, it's sometimes called the Unit type.\footnote{ Look: \D{bool} is a type with \emph{two} values (\D{true} and \D{false}). (), the empty tuple, is the type that has only \emph{one} value. And \D{void} is the type that has \emph{no} value.}
\end{description}
\paragraph{\D{void}-containing tuples\index{void@\D{void}!in tuples}\index{tuple!containing void@containing \D{void}} and empty tuples: } A type tuple may hold the \D{void} type, like any other D type. It `takes a slot' in the tuple and a tuple holding only a \D{void} is \emph{not} the empty tuple.
\begin{dcode}
module emptytuple;
import std.typetuple;
alias TypeTuple!(void) Void;
alias TypeTuple!() Empty;
static assert( !is(Void == Empty) );
static assert(!is( TypeTuple!(int, void, string) == TypeTuple!(int, string)));
\end{dcode}
\subsection{Example: Variadic Functions}\label{variadicfunctions}
Tuples are very useful to make function templates variadic (that is, accept a different number of parameters). Without restriction on the passe-in types, you will need most of the time another function template to process the arguments. A standard example for this is transforming all parameters into a \D{string}:
\index{variadic functions}
\index{compile-time iteration}
\begin{dcode}
module variadic;
string toStrings(string sep = ", ", Args...)(Args args)
{
import std.conv;
string result;
foreach(index, argument; args)
{
result ~= to!string(argument);
if (index != args.length - 1) result ~= sep; // not for the last one
}
return result;
}
unittest
{
assert( toStrings(1, "abc", 3.14, 'a', [1,2,3])
== "1, abc, 3.14, a, [1, 2, 3]");
}
\end{dcode}
If you want to restrict the number of parameters or their types, use template constraints:
\begin{dcode}
int howMany(Args...)(Args args) if (Args.length > 1 && Args.length < 10)
{
return args.length; // == Args.length
}
\end{dcode}
Imagine you a have a bunch of ranges. Since they all have different types, you cannot put them in an array. And since most of them are structs, you cannot cast them to a base type, as you would for classes. So you hold them in a tuple. Then, you need to call the basic range methods on them: calling \DD{popFront} on all of them, etc. Here is a possible way to do that:
\index{tuple!and ranges}
\begin{dcode}
module popallfronts;
import std.range, std.algorithm;
import areallranges;
void popAllFronts(Ranges...)(ref Ranges ranges)
if(areAllRanges!Ranges)
{
foreach(index, range; ranges)
ranges[index].popFront; // to get a ref access
}
unittest
{
auto arr1 = [0,1,2];
auto arr2 = "Hello, World!";
auto arr3 = map!"a*a"(arr1);
popAllFronts(arr1, arr2, arr3);
assert(arr1 == [1,2]);
assert(arr2 == "ello, World!");
assert(equal( arr3, [1,4]));
}
\end{dcode}
It works for any number of ranges, that's cool. And it's checked at compile-time, you cannot pass it an \D{int} discretly, hoping no one will see: it's the job of \DD{areAllRanges}\index{predicate templates!areAllRanges@\DD{areAllRanges}} to verify that. Its code is a classical example of recursion\index{recursion} on type tuples:
\index{predicate template!on type tuples}
\index{type tuple!recursion}
\index{static if@\D{static if}!nested}
\begin{dcode}
module areallranges;
import std.range;
template areAllRanges(Ranges...)
{
static if (Ranges.length == 0) // Base case: stop.
enum areAllRanges = true;
else static if (!isInputRange!(Ranges[0])) // Found a not-range:stop.
enum areAllRanges = false;
else // Continue the recursion
enum areAllRanges = areAllRanges!(Ranges[1..$]);
}
\end{dcode}
People used to languages like lisp/Scheme\index{lisp}\index{Scheme} or Haskell\index{Haskell} will be right at home there. For the others, a little explanation might be in order:
\begin{itemize}
\item when you get a typetuple, either it's empty or it's not.
\item If it's empty, then all the elements it holds are ranges and we return \D{true}.\footnote{ You might not like it, but it's cleaner mathematically this way.}
\item If it's not empty, it has at least one element, which can be accessed by indexing. Let's test it: either it's a range or it's not.
\item If it isn't a range, the iteration stops: not all elements are ranges, we return \D{false}.
\item If it's a range\ldots we have not proved anything, and need to continue.
\end{itemize}
The recursion\index{recursion!areAllRanges@\DD{areAllRanges}} is interesting: by defining an \DD{areAllRanges} manifest constant, we will activate the eponymous template trick\index{eponymous trick} (\ref{eponymous}), which gets initialized to the value obtained by calling the template on a shortened tuple. With slicing, we drop the first type (it was already tested) and continue on the next one. In the end, either we exhausted the tuple (the length == 0 case) or we find a non-range.
\subsection{One-Element Tuples: Accepting Types and Alias}
Sometimes it makes sense for a template to accept either a type parameter\index{template!parameters!type} or an alias\index{template!parameters!alias}. For example, a template that returns a string representing its argument. In that case, since type parameter do not accept symbols as arguments and the same way round for alias, you're doomed to repeat yourself:
\begin{dcode}
module nameof2;
template nameOf(T)
{
enum string nameOf = T.stringof;
}
template nameOf(alias a)
{
enum string nameOf = a.stringof;
}
unittest
{
assert(nameOf!(double[]) == "double[]");
int i;
assert(nameOf!(i) == "i");
}
\end{dcode}
Since tuples can accept both types and alias, you can use them to simplify your code a bit:
\begin{dcode}
module nameof3;
template nameOf(T...) if (T.length == 1) // restricted to one argument
{
enum string nameOf = T[0].stringof;
}
\end{dcode}
\TODO{A better explanation is in order. I'm not that convinced myself.}
\subsection{Example: Inheritance Lists}\label{inheritancelist}
\unfinished{All this section should be rewritten. The compiler is more accepting than I thought.}
Using class templates\index{class template} (\ref{classsyntax}), we might want to adjust the inheritance list at compile-time. Type tuples are a nice way to it: first define a template that alias itself to a type tuple, then have the class inherit from the template:
\index{class template!and type tuples}
\index{type tuple!and class templates}
\begin{dcode}
module interfacelist;
import std.typetuple;
interface I {}
interface J {}
interface K {}
interface L {}
class BaseA {}
class BaseB {}
template Inheritance(Base) if (is(Base == class))
{
static if (is(Base : BaseA))
alias TypeTuple!(Base, I, J, K) Inheritance;
else static if (is(Base : BaseB))
alias TypeTuple!(Base, L) Inheritance;
else
alias Base Inheritance;
}
// Inherits from Base
class MyClass : Inheritance!BaseA { /*...*/ }
class MyOtherClass : Inheritance!BaseB { /*...*/ }
\end{dcode}
Here I templated \DD{Inheritance} on the base class, but you could easily template it on a global \D{enum}, for example. In any case, the selection is abstracted away and the choice-making code is in one place, for you to change it easily.
\TODO{Here I need to rewrite the junction between the two parts of this section.}
Let's begin with something more simple: given a type and a type tuple, eliminate all occurrences of the type in the type tuple.
\index{type tuple!eliminating occurence of a type}
\index{recursion}
\index{is expression@\D{is} expression}
\begin{ndcode}
module eliminate;
import std.typetuple;
template Eliminate(Type, TargetTuple...)
{
static if (TargetTuple.length == 0) // Tuple exhausted,
alias TargetTuple
Eliminate; // job done.
else static if (is(TargetTuple[0] : Type))
alias Eliminate!(Type, TargetTuple[1..$])
Eliminate;
else
alias TypeTuple!(TargetTuple[0], Eliminate!(Type, TargetTuple[1..$]))
Eliminate;
}
unittest
{
alias TypeTuple!(int,double,int,string) Target;
alias Eliminate!(int, Target) NoInts;
static assert(is( NoInts == TypeTuple!(double, string) ));
}
\end{ndcode}
The only difficulty is on line 13: if the first type is not a \DD{Type}, we have to keep it and continue the recursion:
\begin{dcode}
Eliminate!(Type, Type0, Type1, Type2, ...)
->
Type0, Eliminate!(Type, Type1, Type2, ...)
\end{dcode}
We cannot juxtapose types like I just did, we have to wrap them in a template. Phobos defines \DD{TypeTuple} in \std{typetuple} for that use.
Now that we know how to get rid of all occurrences of a type in a type tuple, we have to write a template to eliminate all duplicates. The algorithm is simple: take the first type, eliminate all occurrences of this type in the remaining type tuple. Then call the duplicate elimination anew from the resulting type tuple, while at the same time collecting the first type.
\begin{dcode}
module noduplicates;
import std.typetuple;
import eliminate;
template NoDuplicates(Types...)
{
static if (Types.length == 0)
alias Types NoDuplicates; // No type, nothing to do.
else
alias TypeTuple!(
Types[0]
, NoDuplicates!(Eliminate!(Types[0], Types[1..$]))
) NoDuplicates;
}
static assert(is( NoDuplicates!(int,double,int,string,double)
== TypeTuple!(int,double,string)));
\end{dcode}
By the way, code to do that, also called \DD{NoDuplicates}, is already in Phobos. It can be found in \std{typetuple}. I found coding it again a good exercise in type tuple manipulation\index{type tuple!manipulation}. You can find a few examples of this kind of templates in \autoref{typesorcery}.
The last piece of the puzzle is to get a given class inheritance list. The \D{is} expression\index{is expression@\D{is} expression!type specialization} give us that by way of types specializations (\ref{typespecializations}):
\index{is expression@\D{is} expression!types specializations}
\begin{dcode}
module superlist;
import std.typetuple;
template SuperList(Class) if (is(Class == class))
{
static if (is(Class Parent == super))
alias TypeTuple!(Parent, SuperList!Parent) SuperList;
}
// for Object, is(Object Parent == super)) gives an empty typetuple
template SuperList()
{
alias TypeTuple!() SuperList;
}
unittest
{
class A {}
class B : A {}
class C : A {}
class D : C {}
static assert(is(SuperList!Object == TypeTuple!()));
static assert(is(SuperList!A == TypeTuple!(Object)));
static assert(is(SuperList!B == TypeTuple!(A, Object)));
static assert(is(SuperList!D == TypeTuple!(C, A, Object)));
}
\end{dcode}
\TODO{Rewrite the end.}
Now we are good to go: given a base class, get its inheritance list with \DD{SuperList}. Drop the base class to keep the interfaces. Stitch with the interfaces provided by \DD{Inheritance} and call \DD{NoDuplicates} on it. To make things clearer, I will define many aliases in the template. To keep the use of the eponymous trick\index{eponymous trick}, I will defer the aliasing in another template, as seen in section \ref{eponymous}\index{idiom!two templates}.
\begin{dcode}
module checkedinheritance;
import superlist;
import interfacelist;
template CheckedInheritance(Base)
{
alias CheckedImpl!(Base).Result CheckedInheritance;
}
template CheckedImpl(Base)
{
/* Rewrite the
}
// It works!
class NoError : CheckedInheritance!(MyClass) { /*...*/ }
\end{dcode}
\section{Operator Overloading} \label{operatoroverloading}
\index{operator!overloading}
\unfinished{Oh yes, that's quite not finished. I'm afraid I find D syntax for operator overloading a bit heavy for my tastes. As D code in \LaTeX, it's becoming \emph{very} cumbersome to write.}
D allows users to redefine some operators to enhance readability in code. And guess what? Operator overloading is based on templates. They are described \href{www.dlang.org/operators.html}{here} in the docs.
\subsection{Syntax}
\index{syntax!operator overloading}
Table \ref{table:operatoroverloading} gives you the operator that you can overload and which function template you must define:
\begin{table}
\begin{adjustwidth}{-3.5cm}{} % long table: reducing left margin
\begin{tabular}[htb]{p{5em} c c l}
\hline
\multicolumn{1}{c}{Category}&\multicolumn{1}{c}{Operation} & \multicolumn{1}{c}{Operators} & \multicolumn{1}{c}{Template to define} \\
\hline
& \emph{op}\DD{a} & & \DD{opUnary(}\D{string}\DD{ s)() }\D{if}\DD{ (s == }\emph{op}\DD{)} \\
Unary & \emph{op}\DD{a[i0, i1, in]} & \DD{+}, \DD{-}, \DD{++}, \DD{--} & \DD{opIndexUnary(}\D{string}\DD{ s)(size\_t i0, ...) }\D{if }\DD{(s == }\emph{op}\DD{)} \\
& \emph{op}\DD{a[i..j]} & \DD{*}, \DD{\~{}} & \DD{opSliceUnary(}\D{string}\DD{ s)(size\_t i, size\_t j) }\D{if }\DD{(s == }\emph{op}\DD{)} \\
&\emph{op}\DD{a[]} & & \DD{opSliceUnary(}\D{string}\DD{ s)() }\D{if }\DD{(s == }\emph{op}\DD{)}\\
\hline
& & \DD{+}, \DD{-}, \DD{*}, \DD{/} & \DD{opBinary(}\D{string}\DD{ s, B)(B b)}\\
Binary & \DD{a }\emph{op}\DD{ b} & \DD{\%}, \DD{\^{}\^{}}, \DD{\~{}}, \D{in} & \D{ if }\DD{(s == }\emph{op}\DD{)} \\
& \DD{b }\emph{op}\DD{ a} & \DD{\&}, \DD{|}, \DD{\^{}} & \DD{opBinaryRight(}\D{string}\DD{ s, B)(B b)}\\
& & \DD{$<<$}, \DD{$>>$}, \DD{$>>>$} & \D{ if }\DD{(s == }\emph{op}\DD{)} \\
\hline
& & \DD{+}, \DD{-}, \DD{*}, \DD{/} & \\
Assignment & \DD{a }\emph{op}\DD{= b} & \DD{\%}, \DD{\^{}\^{}}, \DD{\~{}} & \DD{opOpAssign(}\D{string}\DD{ s, B)(B b) }\\
& & \DD{\&}, \DD{|}, \DD{\^{}} & \D{ if }\DD{(s == }\emph{op}\DD{)} \\
& & \DD{$<<$}, \DD{$>>$}, \DD{$>>>$} & \\
\hline
& & \DD{+}, \DD{-}, \DD{*}, \DD{/} & \\
Index & \DD{a[i0,i1,in] }\emph{op}\DD{= b} & \DD{\%}, \DD{\^{}\^{}}, \DD{\~{}} & \DD{opIndexOpAssign(}\D{string}\DD{ s, B)(B b, size\_t i0, ...)}\\
Assignment & & \DD{\&}, \DD{|}, \DD{\^{}} & \D{ if }\DD{(s == }\emph{op}\DD{)} \\
& & \DD{$<<$}, \DD{$>>$}, \DD{$>>>$} & \\
\hline
& \DD{a[i..j] }\emph{op}\DD{= b} & \DD{+}, \DD{-}, \DD{*}, \DD{/} & \DD{opSliceOpAssign(}\D{string}\DD{ s, B)(B b, size\_t i, size\_t j)} \\
Slice & & \DD{\%}, \DD{\^{}\^{}}, \DD{\~{}} & \D{ if }\DD{(s == }\emph{op}\DD{)}\\
Assignment & \DD{a[] }\emph{op}\DD{= b} & \DD{\&}, \DD{|}, \DD{\^{}} & \DD{opSliceOpAssign(}\D{string}\DD{ s, B)(B b)}\\
& & \DD{$<<$}, \DD{$>>$}, \DD{$>>>$} & \D{ if }\DD{(s == }\emph{op}\DD{)} \\
\hline
Cast &\D{cast}\DD{(T)a} & \D{cast()} & \DD{T opCast(T)()} \\
\hline
\end{tabular}
\caption{Operator Overloading}
\label{table:operatoroverloading}
\end{adjustwidth}
\end{table}
Many other operators can be overloaded in D, but do not demand templates.
\subsection{Example: Arithmetic Operators}
\TODO{Tell somewhere that this is possible:}
\begin{dcode}
Foo opBinary(string op:"+")(...) { ... }
\end{dcode}
The idea behind this strange way to overload operators is to allow you to redefine many operators at once with only one method. For example, take this struct wrapping a number:
\begin{dcode}
struct Number(T) if (isNumeric!T)
{
T num;
}
\end{dcode}
To give it the four basic arithmetic operators with another \DD{Number} and another \DD{T}, you define \DD{opBinary} for \DD{+}, \DD{-}, \DD{*} and \DD{/}. This will activate operations were \DD{Number} is on the left. In case it's on the right, you have to define \DD{opBinaryRight}. Since this these overloading tend to use string mixins, I'll use them even though they are introduced only on section \ref{stringmixins}. The basic idea is: string mixins paste code (given as a compile-time string) where they are put.
\index{arithmetic operators}
\index{operator!arithmetic}
\begin{dcode}
module number;
import std.traits;
struct Number(T) if (isNumeric!T)
{
T num;
auto opBinary(string op, U)(U u)
if ((op == "+" || op == "-" || op == "*" || op == "/")
&& ((isNumeric!U) || is(U u == Number!V, V)))
{
mixin("alias typeof(a"~op~"b) Result;
static if (isNumeric!U)
return Number!Result(a"~op~"b);
else
return Number!Result(a"~op~"b.num);");
}
}
\end{dcode}
\DD{op} being a template parameter, it's usable to do compile-time constant folding\index{compile-time!constant folding}: in this case the concatenation of strings to generate D code. The way the code is written, \DD{Number}s respect the global D promotion rules. A \DD{Number!}\D{int} plus a \DD{Number!}\D{double} returns a \DD{Number!}\D{double}.
\subsection{\texorpdfstring{Special Case: \D{in}}
{Special Case: in}}
\subsection{\texorpdfstring{Special Case: \D{cast}}
{Special Case: cast}}
\section{Mixin Templates}\label{mixintemplates}
\index{template!mixin templates}
Up to now, \emph{all} the templates we have seen are instantiated in the same scope than their declaration. Mixin templates have a different behaviour: the code they hold is placed upon instantiation \emph{right at the call site}\index{scope!mixin templates}. They are thus used in a completely different way than other templates.
\subsection{Syntax}\label{mixintemplatessyntax}
To distinguish standard templates from mixin templates, the latter have slightly different syntax. Here is how they are declared and called:
\index{syntax!mixin templates}
\begin{dcode}
/* Declaration */
mixin template NewFunctionality(T,U) { ... }
/* Instantiation */
class MyClass(T,U,V)
{
mixin NewFunctionality!(U,V);
...
}
\end{dcode}
As you can see, you put \D{mixin} before the declaration and \D{mixin} before the instantiation call. All other templates niceties (constraints, default values, \ldots) are still there for your perusal. Symbols lookup is done in the local scope\index{scope!mixin templates!symbols lookup} and the resulting code is included where the call was made, therefore injecting new functionality\index{scope!mixin templates!injecting functionality}.
As far as I know, there is no special syntax for function, class and struct templates to be mixin templates. You will have to wrap them in a standard \D{template} declaration. In the same idea, there is no notion of eponymous trick with mixin templates: there is no question of how to give access to the template's content, since the template is cracked open for you and its very content put in your code.
\TODO{Test for mixin T foo(T)(T t) { return t;}}
By the way, you \emph{cannot} mix a standard template in. It used to be the case, but it's not possible anymore. Now mixin templates and non-mixin ones are strictly separated cousins.
\subsection{Mixing Code In}\label{mixincodein}
What good are these cousins of the templates we've seen so far? They give you a nice way to place parameterized implementation inside a class or a struct. Once more, templates are a way to reduce boilerplate code. If some piece of code appears in different places in your code (for example, in structs, where there is no inheritance to avoid code duplication), you should look for a way to put it in a mixin template.
Also, you can put small functionalities in mixin templates, giving client code access to them to chose how they want to build their types.
Note that the code you place inside a mixin template doesn't have to make sense by itself (it can refer to \D{this} or any not-yet-defined symbols). It just has to be syntactically correct D code.
For example, remember the operator overloading code we saw in section \ref{operatoroverloading}? Here is a mixin containing concatenating functionality:
\index{mixin templates}
\index{operator!concatenation, (~)@concatenation, (\DD{\~})}
\begin{dcode}
module mixinconcatenate;
import std.typecons;
mixin template Concatenate()
{
Tuple!(typeof(this), U) opBinary(string op, U)(U u)
if (op == "~")
{
return tuple(this, u);
}
}
\end{dcode}
As you can see, it uses \D{this}, even though there is no struct or class in sight. It's used like this, to give concatenation (as tuples) ability to a struct:
\begin{dcode}
module usingmixinconcatenate;
import std.typecons;
import mixinconcatenate;
struct S
{
mixin Concatenate;
}
unittest
{
S s,t;
auto result = s ~ t;
assert(result == tuple(s,t));
}
\end{dcode}
The idea to take back home is: the concatenation code is written once. It is then an offered functionality for any client scope\index{scope!client} (type) that want it. It could easily have been arithmetic operations, \D{cast} operations or new methods like \DD{log}, \DD{register}, new members or whatever else. Build you own set of mixins and use them freely. And remember they are not limited to classes and structs: you can also use them in functions, module scopes, other templates\ldots
\aparte{Limitations\index{mixin templates!limitations}}{ Mixin templates inject code at the local scope\index{scope!local scope}. They cannot add an \D{invariant} clause in a class, or \D{in}/\D{out} clauses in a function. They can be injected into an \D{invariant}/\D{in}/\D{out} clause.}
\subsection{Mixin Example: Subscriber and Stack}
This example comes from Bj\"{o}rn Lietz-Spendig, who was kind enough to allow me to use it there. Thanks Bj\"{o}rn!
We will define two mixin templates \DD{PublisherMixin} and \DD{StackMixin}, the first one implementing a subscription/unsubscription engine, the second providing the standard stack operations (\DD{push}, \DD{pop},\ldots). I'd like you to notice two important things here:
\begin{itemize}
\item D allowing local imports, \DD{PublisherMixin} imports the machinery necessary for it to function: \stdanchor{functional}{toDelegate} and \std{stdio}. Local imports really allow D template mixins to provide a nicely wrapped functionality as a coherent whole.
\item \D{alias typeof}\DD{(}\D{this}\DD{)} (here called \DD{Me}) is also a nice feature to remember: the mixin will 'look around', get the local \D{this} type and can then provide generic ready-to-be-used code.
\end{itemize}
\begin{dcode}
module publisher;
public mixin template PublisherMixin()
{
import std.functional : toDelegate;
import std.stdio;
alias void delegate(Object sender, string event) CallBack;
alias void function(Object sender, string event) CallBackFun;
bool[CallBack] callBacks; // int[0][CallBack] may be even smaller
//Register subscriber
void register(CallBack callBack)
{
// Ensure subscriber is not yet registered.
if (callBack in callBacks)
writeln("Subscriber is already registered.");
else
callBacks[callBack] = true; //from;
}
// Register Subscriber via function ptr.
void register(CallBackFun callBackFun)
{
register( toDelegate(callBackFun) );
}
// Remove Subscriber
void unRegister(CallBack callBack)
{