root/trunk/docsrc/template-mixin.dd

Revision 2140, 6.4 kB (checked in by walter, 2 years ago)

bugzilla 1351 Discrepancies in the language specification

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(SPEC_S Template Mixins,
4
5     A $(I TemplateMixin) takes an arbitrary set of declarations from
6     the body of a $(I TemplateDeclaration) and inserts them
7     into the current context.
8
9 $(GRAMMAR
10 $(GNAME TemplateMixinDeclaration):
11     $(V2 $(B mixin)) $(B template) $(TEMPLATEIDENTIFIER) $(B $(LPAREN)) $(TEMPLATEPARAMETERLIST) $(B $(RPAREN)) $(V2 $(GLINK Constraint)$(SUB $(I opt)))
12         $(B {) $(LINK2 module.html#DeclDefs, DeclDefs) $(B })
13
14 $(GNAME TemplateMixin):
15     $(B mixin) $(TEMPLATEIDENTIFIER) $(B ;)
16     $(B mixin) $(TEMPLATEIDENTIFIER) $(GLINK MixinIdentifier) $(B ;)
17     $(B mixin) $(TEMPLATEIDENTIFIER) $(B !$(LPAREN)) $(TEMPLATEARGUMENTLIST) $(B $(RPAREN)) $(B ;)
18     $(B mixin) $(TEMPLATEIDENTIFIER) $(B !$(LPAREN)) $(TEMPLATEARGUMENTLIST) $(B $(RPAREN)) $(GLINK MixinIdentifier) $(B ;)
19
20 $(GNAME MixinIdentifier):
21     $(I Identifier)
22 )
23
24     $(P A $(I TemplateMixin) can occur in declaration lists of modules,
25     classes, structs, unions, and as a statement.
26     The $(I TemplateIdentifier) refers to a $(I TemplateDeclaration).
27     If the $(I TemplateDeclaration) has no parameters, the mixin
28     form that has no !($(I TemplateArgumentList))
29     can be used.
30     )
31
32     $(P Unlike a template instantiation, a template mixin's body is evaluated
33     within the scope where the mixin appears, not where the template declaration
34     is defined. It is analogous to cutting and pasting the body of
35     the template into the location of the mixin. It is useful for injecting
36     parameterized $(SINGLEQUOTE boilerplate) code, as well as for creating
37     templated nested functions, which is not possible with
38     template instantiations.
39     )
40
41 ------
42 $(V2 mixin) template Foo()
43 {
44     int x = 5;
45 }
46
47 $(B mixin Foo;)
48
49 struct Bar
50 {
51     $(B mixin Foo;)
52 }
53
54 void test()
55 {
56     writefln("x = %d", x);      // prints 5
57     {   Bar b;
58     int x = 3;
59
60     writefln("b.x = %d", b.x);  // prints 5
61     writefln("x = %d", x);      // prints 3
62     {
63         $(B mixin Foo;)
64         writefln("x = %d", x);  // prints 5
65         x = 4;
66         writefln("x = %d", x);  // prints 4
67     }
68     writefln("x = %d", x);      // prints 3
69     }
70     writefln("x = %d", x);      // prints 5
71 }
72 ------
73
74     Mixins can be parameterized:
75
76 ------
77 $(V2 mixin) template Foo(T)
78 {
79     T x = 5;
80 }
81
82 $(B mixin Foo!(int);)       // create x of type int
83 ------
84
85     Mixins can add virtual functions to a class:
86
87 ------
88 $(V2 mixin) template Foo()
89 {
90     void func() { writefln("Foo.func()"); }
91 }
92
93 class Bar
94 {
95     $(B mixin Foo);
96 }
97
98 class Code : Bar
99 {
100     void func() { writefln("Code.func()"); }
101 }
102
103 void test()
104 {
105     Bar b = new Bar();
106     b.func();       // calls Foo.func()
107
108     b = new Code();
109     b.func();       // calls Code.func()
110 }
111 ------
112
113     Mixins are evaluated in the scope of where they appear, not the scope
114     of the template declaration:
115
116 ------
117 int y = 3;
118
119 $(V2 mixin) template Foo()
120 {
121     int abc() { return y; }
122 }
123
124 void test()
125 {
126     int y = 8;
127     $(B mixin Foo;) // local y is picked up, not global y
128     assert(abc() == 8);
129 }
130 ------
131
132     Mixins can parameterize symbols using alias parameters:
133
134 ------
135 $(V2 mixin) template Foo(alias b)
136 {
137     int abc() { return b; }
138 }
139
140 void test()
141 {
142     int y = 8;
143     $(B mixin Foo!(y);)
144     assert(abc() == 8);
145 }
146 ------
147
148     This example uses a mixin to implement a generic Duff's device
149     for an arbitrary statement (in this case, the arbitrary statement
150     is in bold). A nested function is generated as well as a
151     delegate literal, these can be inlined by the compiler:
152
153 ------
154 $(V2 mixin) template duffs_device(alias id1, alias id2, alias s)
155 {
156     void duff_loop()
157     {
158     if (id1 < id2)
159     {
160         typeof(id1) n = (id2 - id1 + 7) / 8;
161         switch ((id2 - id1) % 8)
162         {
163         case 0:        do {  s();
164         case 7:              s();
165         case 6:              s();
166         case 5:              s();
167         case 4:              s();
168         case 3:              s();
169         case 2:              s();
170         case 1:              s();
171                   } while (--n > 0);
172         }
173     }
174     }
175 }
176
177 void foo() { writefln("foo"); }
178
179 void test()
180 {
181     int i = 1;
182     int j = 11;
183
184     mixin duffs_device!(i, j, $(B delegate { foo(); }) );
185     duff_loop();    // executes foo() 10 times
186 }
187 ------
188
189 <h2>Mixin Scope</h2>
190
191     The declarations in a mixin are $(SINGLEQUOTE imported) into the surrounding
192     scope. If the name of a declaration in a mixin is the same
193     as a declaration in the surrounding scope, the surrounding declaration
194     overrides the mixin one:
195
196 ------
197 int x = 3;
198
199 $(V2 mixin) template Foo()
200 {
201     int x = 5;
202     int y = 5;
203 }
204
205 $(B mixin Foo;)
206 int y = 3;
207
208 void test()
209 {
210     writefln("x = %d", x);  // prints 3
211     writefln("y = %d", y);  // prints 3
212 }
213 ------
214
215     If two different mixins are put in the same scope, and each
216     define a declaration with the same name, there is an ambiguity
217     error when the declaration is referenced:
218
219 ------
220 $(V2 mixin) template Foo()
221 {
222     int x = 5;
223     void func(int x) { }
224 }
225
226 $(V2 mixin) template Bar()
227 {
228     int x = 4;
229     void func() { }
230 }
231
232 $(B mixin Foo;)
233 $(B mixin Bar;)
234
235 void test()
236 {
237     writefln("x = %d", x);  // error, x is ambiguous
238     func();     // error, func is ambiguous
239 }
240 ------
241     $(P The call to $(B func()) is ambiguous because
242     Foo.func and Bar.func are in different scopes.
243     )
244
245     $(P If a mixin has a $(I MixinIdentifier), it can be used to
246     disambiguate:
247     )
248 ------
249 int x = 6;
250
251 $(V2 mixin) template Foo()
252 {
253     int x = 5;
254     int y = 7;
255     void func() { }
256 }
257
258 $(V2 mixin) template Bar()
259 {
260     int x = 4;
261     void func() { }
262 }
263
264 $(B mixin Foo F;)
265 $(B mixin Bar B;)
266
267 void test()
268 {
269     writefln("y = %d", y);  // prints 7
270     writefln("x = %d", x);  // prints 6
271     writefln("F.x = %d", F.x);  // prints 5
272     writefln("B.x = %d", B.x);  // prints 4
273     F.func();           // calls Foo.func
274     B.func();           // calls Bar.func
275 }
276 ------
277     $(P Alias declarations can be used to overload together
278     functions declared in different mixins:)
279
280 -----
281 $(V2 mixin) template Foo()
282 {
283     void func(int x) {  }
284 }
285
286 $(V2 mixin) template Bar()
287 {
288     void func() {  }
289 }
290
291 mixin Foo!() F;
292 mixin Bar!() B;
293
294 $(B alias F.func func;)
295 $(B alias B.func func;)
296
297 void main()
298 {
299     func(); // calls B.func
300     func(1);    // calls F.func
301 }
302 -----
303
304
305     $(P A mixin has its own scope, even if a declaration is overridden
306     by the enclosing one:)
307
308 ------
309 int x = 4;
310
311 $(V2 mixin) template Foo()
312 {
313     int x = 5;
314     int bar() { return x; }
315 }
316
317 $(B mixin Foo;)
318
319 void test()
320 {
321     writefln("x = %d", x);      // prints 4
322     writefln("bar() = %d", bar());  // prints 5
323 }
324 ------
325
326 )
327
328 Macros:
329     TITLE=Mixins
330     WIKI=Mixin
331     TEMPLATEIDENTIFIER=$(LINK2 template.html#TemplateIdentifier, $(I TemplateIdentifier))
332     TEMPLATEPARAMETERLIST=$(LINK2 template.html#TemplateParameterList, $(I TemplateParameterList))
333     TEMPLATEARGUMENTLIST=$(LINK2 template.html#TemplateArgumentList, $(I TemplateArgumentList))
334     FOO=
Note: See TracBrowser for help on using the browser.