root/trunk/docsrc/tuple.dd

Revision 2040, 7.8 kB (checked in by walter, 2 years ago)

typography

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(D_S Tuples,
4
5     $(P A tuple is a sequence of elements. Those elements can
6     be types, expressions, or aliases.
7     The number and elements of a tuple are fixed at compile time;
8     they cannot be changed at run time.
9     )
10
11     $(P Tuples have characteristics of both
12     structs and arrays. Like structs, the tuple
13     elements can be of different types. Like arrays,
14     the elements can be accessed via indexing.
15     )
16
17     $(P So how does one construct a tuple? There isn't a specific
18     tuple literal syntax. But since variadic template parameters
19     create tuples, we can define a template to create one:
20     )
21
22 ---
23 template Tuple(E...)
24 {
25     alias E Tuple;
26 }
27 ---
28
29     $(P and it's used like:)
30
31 ---
32 Tuple!(int, long, float)    // create a tuple of 3 types
33 Tuple!(3, 7, 'c')       // create a tuple of 3 expressions
34 Tuple!(int, 8)          // create a tuple of a type and an expression
35 ---
36
37     $(P In order to symbolically refer to a tuple, use an alias:)
38
39 ---
40 alias Tuple!(float, float, 3) TP; // TP is now a tuple of two floats and 3
41 ---
42
43     $(P Tuples can be used as arguments to templates, and if so
44     they are $(SINGLEQUOTE flattened) out into a list of arguments.
45     This makes it straightforward to append a new element to
46     an existing tuple or concatenate tuples:)
47
48 ---
49 alias Tuple!(TP, 8) TR;  // TR is now float,float,3,8
50 alias Tuple!(TP, TP) TS; // TS is float,float,3,float,float,3
51 ---
52
53     $(P Tuples share many characteristics with arrays.
54     For starters, the number of elements in a tuple can
55     be retrieved with the $(B .length) property:)
56
57 ---
58 TP.length   // evaluates to 3
59 ---
60
61     $(P Tuples can be indexed:)
62
63 ---
64 TP[1] f = TP[2];    // f is declared as a float and initialized to 3
65 ---
66
67     $(P and even sliced:)
68
69 ---
70 alias TP[0..length-1] TQ; // TQ is now the same as Tuple!(float, float)
71 ---
72
73     $(P Yes, $(B length) is defined within the [ ]s.
74     There is one restriction: the indices for indexing and slicing
75     must be evaluatable at compile time.)
76
77 ---
78 void foo(int i)
79 {
80     TQ[i] x;        // error, i is not constant
81 }
82 ---
83
84     $(P These make it simple to produce the $(SINGLEQUOTE head) and $(SINGLEQUOTE tail)
85     of a tuple. The head is just TP[0], the tail
86     is TP[1 .. length].
87     Given the head and tail, mix with a little conditional
88     compilation, and we can implement some classic recursive
89     algorithms with templates.
90     For example, this template returns a tuple consisting
91     of the trailing type arguments $(I TL) with the first occurrence
92     of the first type argument $(I T) removed:
93     )
94 ---
95 template Erase(T, TL...)
96 {
97     static if (TL.length == 0)
98     // 0 length tuple, return self
99         alias TL Erase;
100     else static if (is(T == TL[0]))
101     // match with first in tuple, return tail
102         alias TL[1 .. length] Erase;
103     else
104     // no match, return head concatenated with recursive tail operation
105         alias Tuple!(TL[0], Erase!(T, TL[1 .. length])) Erase;
106 }
107 ---
108
109 <h3>Type Tuples</h3>
110
111     $(P If a tuple's elements are solely types,
112     it is called a $(I TypeTuple)
113     (sometimes called a type list).
114     Since function parameter lists are a list of types,
115     a type tuple can be retrieved from them.
116     One way is using an $(ISEXPRESSION):
117     )
118
119 ---
120 int foo(int x, long y);
121
122 ...
123 static if (is(foo P == function))
124     alias P TP;
125 // TP is now the same as Tuple!(int, long)
126 ---
127
128     $(P This is generalized in the template
129     $(LINK2 phobos/std_traits.html, std.traits).ParameterTypeTuple:
130     )
131
132 ---
133 import std.traits;
134
135 ...
136 alias ParameterTypeTuple!(foo) TP;  // TP is the tuple (int, long)
137 ---
138
139     $(P $(I TypeTuple)s can be used to declare a function:)
140
141 ---
142 float bar(TP);  // same as float bar(int, long)
143 ---
144
145     $(P If implicit function template instantiation is being done,
146     the type tuple representing the parameter types can be deduced:
147     )
148 ---
149 int foo(int x, long y);
150
151 void Bar(R, P...)(R function(P))
152 {
153     writefln("return type is ", typeid(R));
154     writefln("parameter types are ", typeid(P));
155 }
156
157 ...
158 Bar(&foo);
159 ---
160
161     $(P Prints:)
162
163 $(CONSOLE
164 return type is int
165 parameter types are (int,long)
166 )
167
168     $(P Type deduction can be used to create a function that
169     takes an arbitrary number and type of arguments:)
170
171 ---
172 void Abc(P...)(P p)
173 {
174     writefln("parameter types are ", typeid(P));
175 }
176
177 Abc(3, 7L, 6.8);
178 ---
179
180     $(P Prints:)
181
182 $(CONSOLE
183 parameter types are (int,long,double)
184 )
185
186     $(P For a more comprehensive treatment of this aspect, see
187     $(LINK2 variadic-function-templates.html, Variadic Templates).
188     )
189
190
191 <h3>Expression Tuples</h3>
192
193     $(P If a tuple's elements are solely expressions,
194     it is called an $(I ExpressionTuple).
195     The Tuple template can be used to create one:
196     )
197
198 ---
199 alias Tuple!(3, 7L, 6.8) ET;
200
201 ...
202 writefln(ET);            // prints 376.8
203 writefln(ET[1]);         // prints 7
204 writefln(ET[1..length]); // prints 76.8
205 ---
206
207     $(P It can be used to create an array literal:)
208
209 ---
210 alias Tuple!(3, 7, 6) AT;
211
212 ...
213 int[] a = [AT];     // same as [3,7,6]
214 ---
215
216     $(P The data fields of a struct or class can be
217     turned into an expression tuple using the $(B .tupleof)
218     property:)
219
220 ---
221 struct S { int x; long y; }
222
223 void foo(int a, long b)
224 {
225     writefln(a, b);
226 }
227
228 ...
229 S s;
230 s.x = 7;
231 s.y = 8;
232 foo(s.x, s.y);  // prints 78
233 foo(s.tupleof); // prints 78
234 s.tupleof[1] = 9;
235 s.tupleof[0] = 10;
236 foo(s.tupleof); // prints 109
237 s.tupleof[2] = 11;  // error, no third field of S
238 ---
239
240     $(P A type tuple can be created from the data fields
241     of a struct using $(B typeof):)
242
243 ---
244 writefln(typeid(typeof(S.tupleof)));    // prints (int,long)
245 ---
246
247     $(P This is encapsulated in the template
248     $(LINK2 phobos/std_traits.html, std.traits).FieldTypeTuple.
249     )
250
251 <h3>Looping</h3>
252
253     $(P While the head-tail style of functional programming works
254     with tuples, it's often more convenient to use a loop.
255     The $(I ForeachStatement) can loop over either $(I TypeTuple)s
256     or $(I ExpressionTuple)s.
257     )
258
259 ---
260 alias Tuple!(int, long, float) TL;
261 foreach (i, T; TL)
262     writefln("TL[%d] = ", i, typeid(T));
263
264 alias Tuple!(3, 7L, 6.8) ET;
265 foreach (i, E; ET)
266     writefln("ET[%d] = ", i, E);
267 ---
268
269     $(P Prints:)
270
271 $(CONSOLE
272 TL[0] = int
273 TL[1] = long
274 TL[2] = float
275 ET[0] = 3
276 ET[1] = 7
277 ET[2] = 6.8
278 )
279
280 <h3>Tuple Declarations</h3>
281
282     $(P A variable declared with a $(I TypeTuple) becomes an
283     $(I ExpressionTuple):)
284
285 ---
286 alias Tuple!(int, long) TL;
287
288 void foo(TL tl)
289 {
290     writefln(tl, tl[1]);
291 }
292
293 foo(1, 6L); // prints 166
294 ---
295
296 <h3>Putting It All Together</h3>
297
298     $(P These capabilities can be put together to implement
299     a template that will encapsulate all the arguments to
300     a function, and return a delegate that will call the function
301     with those arguments.)
302
303 ---
304 import std.stdio;
305
306 R delegate() CurryAll(Dummy=void, R, U...)(R function(U) dg, U args)
307 {
308     struct Foo
309     {
310     typeof(dg) dg_m;
311     U args_m;
312
313     R bar()
314     {
315         return dg_m(args_m);
316     }
317     }
318
319     Foo* f = new Foo;
320     f.dg_m = dg;
321     foreach (i, arg; args)
322     f.args_m[i] = arg;
323     return &f.bar;
324 }
325
326 R delegate() CurryAll(R, U...)(R delegate(U) dg, U args)
327 {
328     struct Foo
329     {
330     typeof(dg) dg_m;
331     U args_m;
332
333     R bar()
334     {
335         return dg_m(args_m);
336     }
337     }
338
339     Foo* f = new Foo;
340     f.dg_m = dg;
341     foreach (i, arg; args)
342     f.args_m[i] = arg;
343     return &f.bar;
344 }
345
346
347 void main()
348 {
349     static int plus(int x, int y, int z)
350     {
351     return x + y + z;
352     }
353
354     auto plus_two = CurryAll(&plus, 2, 3, 4);
355     writefln("%d", plus_two());
356     assert(plus_two() == 9);
357
358     int minus(int x, int y, int z)
359     {
360     return x + y + z;
361     }
362
363     auto minus_two = CurryAll(&minus, 7, 8, 9);
364     writefln("%d", minus_two());
365     assert(minus_two() == 24);
366 }
367 ---
368
369     $(P The reason for the $(I Dummy) parameter is that one
370     cannot overload two templates with the same parameter list.
371     So we make them different by giving one a dummy parameter.
372     )
373
374 <h3>Future Directions</h3>
375
376     $(UL
377     $(LI Return tuples from functions.)
378     $(LI Use operators on tuples, like =, +=, etc.)
379     $(LI Have tuple properties like $(B .init) which will apply
380     the property to each of the tuple members.)
381     )
382
383 )
384
385 Macros:
386     TITLE=Tuples
387     WIKI=Tuples
388 META_KEYWORDS=D Programming Language, template metaprogramming,
389 variadic templates, tuples, currying
390 META_DESCRIPTION=Tuples in the D programming language
Note: See TracBrowser for help on using the browser.