$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Template Mixins, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_SUBITEMS parameters, Mixin Parameters, $(HEADERNAV_ITEM example, Example) ) $(HEADERNAV_SUBITEMS mixin_scope, Mixin Scope, $(HEADERNAV_ITEM resolving_ambiguities, Resolving Ambiguities) ) $(HEADERNAV_SUBITEMS aggregate_types, Aggregate Type Mixins, $(HEADERNAV_ITEM virtual_functions, Mixin Virtual Functions) $(HEADERNAV_ITEM destructors, Mixin Destructors) ) ) $(DDOC_BLANKLINE ) $(P A $(I TemplateMixin) takes an arbitrary set of declarations from the body of a $(GLINK2 template, TemplateDeclaration) and inserts them into the current context.) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME TemplateMixinDeclaration): $(D mixin) $(D template) $(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters) $(GLINK2 template, Constraint)$(OPT ) $(D {) $(GLINK2 module, DeclDefs)$(OPT ) $(D }) $(DDOC_BLANKLINE ) $(GNAME TemplateMixin): $(D mixin) $(GLINK MixinTemplateName) $(GLINK2 template, TemplateArguments)$(OPT ) $(GLINK_LEX Identifier)$(OPT ) $(D ;) $(DDOC_BLANKLINE ) $(GNAME MixinTemplateName): $(D .) $(GLINK MixinQualifiedIdentifier) $(GLINK MixinQualifiedIdentifier) $(GLINK2 type, Typeof) $(D .) $(GLINK MixinQualifiedIdentifier) $(DDOC_BLANKLINE ) $(GNAME MixinQualifiedIdentifier): $(GLINK_LEX Identifier) $(GLINK_LEX Identifier) $(D .) $(GSELF MixinQualifiedIdentifier) $(GLINK2 template, TemplateInstance) $(D .) $(GSELF MixinQualifiedIdentifier) ) $(DDOC_BLANKLINE ) $(P A $(I TemplateMixin) can occur in declaration lists of modules, classes, structs, unions, or as a statement. $(I MixinTemplateName) must refer to a $(I TemplateDeclaration) or $(I TemplateMixinDeclaration). If the $(I TemplateDeclaration) requires no parameters, $(I TemplateArguments) can be omitted. ) $(DDOC_BLANKLINE ) $(P Unlike a $(DDSUBLINK spec/template, instantiation_scope, template instantiation), a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined. It is analogous to cutting and pasting the body of the template into the location of the mixin into a $(LINK2 #mixin_scope, nested scope). It is useful for injecting parameterized $(SINGLEQUOTE boilerplate) code, as well as for creating templated nested functions, which is not always possible with template instantiations. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int) y = 3; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) abc() { $(D_KEYWORD return) y; } } $(D_KEYWORD void) test() { $(D_KEYWORD int) y = 8; $(D_KEYWORD mixin) Foo; $(D_COMMENT // local y is picked up, not global y ) $(D_KEYWORD assert)(abc() == 8); } ) ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) x = 5; } $(D_KEYWORD mixin) Foo; $(D_KEYWORD struct) Bar { $(D_KEYWORD mixin) Foo; } $(D_KEYWORD void) main() { writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 5 ) { Bar b; $(D_KEYWORD int) x = 3; writeln($(D_STRING "b.x = "), b.x); $(D_COMMENT // prints 5 ) writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 3 ) { $(D_KEYWORD mixin) Foo; writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 5 ) x = 4; writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 4 ) } writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 3 ) } writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 5 )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 parameters, Mixin Parameters)

$(DDOC_BLANKLINE ) $(P Mixins can be $(DDSUBLINK spec/template, parameters, parameterized):) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD mixin) $(D_KEYWORD template) Foo(T) { T x = 5; } $(D_KEYWORD mixin) Foo!($(D_KEYWORD int)); $(D_COMMENT // create x of type int )) $(DDOC_BLANKLINE ) $(P Mixins can parameterize symbols using $(DDSUBLINK spec/template, aliasparameters, alias parameters):) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD mixin) $(D_KEYWORD template) Foo($(D_KEYWORD alias) b) { $(D_KEYWORD int) abc() { $(D_KEYWORD return) b; } } $(D_KEYWORD void) test() { $(D_KEYWORD int) y = 8; $(D_KEYWORD mixin) Foo!(y); $(D_KEYWORD assert)(abc() == 8); } ) $(DDOC_BLANKLINE )

$(LNAME2 example, Example)

$(DDOC_BLANKLINE ) $(P This example uses a mixin to implement a generic Duff's device for an arbitrary statement (in this case, the arbitrary statement is in bold). A nested function is generated as well as a delegate literal, these can be inlined by the compiler:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD mixin) $(D_KEYWORD template) duffs_device($(D_KEYWORD alias) low, $(D_KEYWORD alias) high, $(D_KEYWORD alias) fun) { $(D_KEYWORD void) duff_loop() { $(D_KEYWORD if) (low < high) { $(D_KEYWORD auto) n = (high - low + 7) / 8; $(D_KEYWORD switch) ((high - low) % 8) { $(D_KEYWORD case) 0: $(D_KEYWORD do) { fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 7: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 6: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 5: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 4: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 3: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 2: fun(); $(D_KEYWORD goto) $(D_KEYWORD case); $(D_KEYWORD case) 1: fun(); $(D_KEYWORD continue); $(D_KEYWORD default): $(D_KEYWORD assert)(0, $(D_STRING "Impossible")); } $(D_KEYWORD while) (--n > 0); } } } } $(D_KEYWORD void) main() { $(D_KEYWORD int) i = 1; $(D_KEYWORD int) j = 11; $(D_KEYWORD mixin) duffs_device!(i, j, $(D_KEYWORD delegate) { writeln($(D_STRING "foo")); }); duff_loop(); $(D_COMMENT // executes foo$(LPAREN)$(RPAREN ) 10 times )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 mixin_scope, Mixin Scope)

$(DDOC_BLANKLINE ) $(P The declarations in a mixin are placed in a nested scope and then $(SINGLEQUOTE imported) into the surrounding scope. If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD int) x = 3; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) x = 5; $(D_KEYWORD int) y = 5; } $(D_KEYWORD mixin) Foo; $(D_KEYWORD int) y = 3; $(D_KEYWORD void) main() { writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 3 ) writeln($(D_STRING "y = "), y); $(D_COMMENT // prints 3 )} ) ) $(DDOC_BLANKLINE ) $(P A mixin has its own scope, even if a declaration is overridden by the enclosing one:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD int) x = 4; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) x = 5; $(D_KEYWORD int) bar() { $(D_KEYWORD return) x; } } $(D_KEYWORD mixin) Foo; $(D_KEYWORD void) main() { writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 4 ) writeln($(D_STRING "bar$(LPAREN)$(RPAREN ) = "), bar()); $(D_COMMENT // prints 5 )} ) ) $(DDOC_BLANKLINE ) $(P If two different mixins are put in the same scope, and each define a declaration with the same name, there is an ambiguity error when the declaration is referenced:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) x = 5; $(D_KEYWORD void) func($(D_KEYWORD int) x) { } } $(D_KEYWORD mixin) $(D_KEYWORD template) Bar() { $(D_KEYWORD int) x = 4; $(D_KEYWORD void) func($(D_KEYWORD long) x) { } } $(D_KEYWORD mixin) Foo; $(D_KEYWORD mixin) Bar; $(D_KEYWORD void) main() { writeln($(D_STRING "x = "), x); $(D_COMMENT // error, x is ambiguous ) func(1); $(D_COMMENT // error, func is ambiguous )} ) ) $(P The call to $(D func()) is ambiguous because Foo.func and Bar.func are in different scopes. ) $(DDOC_BLANKLINE )

$(LNAME2 resolving_ambiguities, Resolving Ambiguities)

$(DDOC_BLANKLINE ) $(P If a mixin has an $(I Identifier), it can be used to disambiguate between conflicting symbols: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD int) x = 6; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD int) x = 5; $(D_KEYWORD int) y = 7; $(D_KEYWORD void) func() { } } $(D_KEYWORD mixin) $(D_KEYWORD template) Bar() { $(D_KEYWORD int) x = 4; $(D_KEYWORD void) func() { } } $(D_KEYWORD mixin) Foo F; $(D_KEYWORD mixin) Bar B; $(D_KEYWORD void) main() { writeln($(D_STRING "y = "), y); $(D_COMMENT // prints 7 ) writeln($(D_STRING "x = "), x); $(D_COMMENT // prints 6 ) writeln($(D_STRING "F.x = "), F.x); $(D_COMMENT // prints 5 ) writeln($(D_STRING "B.x = "), B.x); $(D_COMMENT // prints 4 ) F.func(); $(D_COMMENT // calls Foo.func ) B.func(); $(D_COMMENT // calls Bar.func )} ) ) $(P Alias declarations can be used to form an $(DDSUBLINK spec/function, overload-sets, overload set) of functions declared in different mixins:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD void) func($(D_KEYWORD int) x) { } } $(D_KEYWORD mixin) $(D_KEYWORD template) Bar() { $(D_KEYWORD void) func($(D_KEYWORD long) x) { } } $(D_KEYWORD mixin) Foo!() F; $(D_KEYWORD mixin) Bar!() B; $(D_KEYWORD alias) func = F.func; $(D_KEYWORD alias) func = B.func; $(D_KEYWORD void) main() { func(1); $(D_COMMENT // calls B.func ) func(1L); $(D_COMMENT // calls F.func )} ) $(DDOC_BLANKLINE )

$(LNAME2 aggregate_types, Aggregate Type Mixins)

$(DDOC_BLANKLINE )

$(LNAME2 virtual_functions, Mixin Virtual Functions)

$(DDOC_BLANKLINE ) $(P Mixins can add virtual functions to a class:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio : writeln; $(D_KEYWORD mixin) $(D_KEYWORD template) Foo() { $(D_KEYWORD void) func() { writeln($(D_STRING "Foo.func$(LPAREN)$(RPAREN )")); } } $(D_KEYWORD class) Bar { $(D_KEYWORD mixin) Foo; } $(D_KEYWORD class) Code : Bar { $(D_KEYWORD override) $(D_KEYWORD void) func() { writeln($(D_STRING "Code.func$(LPAREN)$(RPAREN )")); } } $(D_KEYWORD void) main() { Bar b = $(D_KEYWORD new) Bar(); b.func(); $(D_COMMENT // calls Foo.func$(LPAREN)$(RPAREN ) ) b = $(D_KEYWORD new) Code(); b.func(); $(D_COMMENT // calls Code.func$(LPAREN)$(RPAREN ) )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 destructors, Mixin Destructors)

$(DDOC_BLANKLINE ) $(P An aggregate type can mixin additional destructors. Destructors are run in the opposite order to declaration order.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio; $(D_KEYWORD mixin) $(D_KEYWORD template) addNewDtor() { ~$(D_KEYWORD this)() { writeln($(D_STRING "Mixin dtor")); } } $(D_KEYWORD struct) S { ~$(D_KEYWORD this)() { writeln($(D_STRING "Struct dtor")); } $(D_KEYWORD mixin) addNewDtor; } $(D_KEYWORD void) main() { S s; $(D_COMMENT // prints `Mixin dtor` ) $(D_COMMENT // prints `Struct dtor` )} ) ) $(DDOC_BLANKLINE ) $(SPEC_SUBNAV_PREV_NEXT template, Templates, contracts, Contract Programming) ) )