Mixins
Mixins quer dizer coisas diferentes em linguagens de programação diferentes. Em D, um mixin é um conjunto de declarações arbitrario do corpo de uma TemplateDeclaration e inserí-las no contexto atual.TemplateMixin:Um TemplateMixin pode ocorrer em listas de declaração de módulos, classes, uniões e como uma instrução. O TemplateIdentifier se refere à uma TemplateDeclaration. Se a TemplateDeclaration não tem parâmetros, a forma do mixin que não tem !(TemplateArgumentList) pode ser usada.
mixin TemplateIdentifier ;
mixin TemplateIdentifier MixinIdentifier ;
mixin TemplateIdentifier !() TemplateArgumentList ;
mixin TemplateIdentifier !() TemplateArgumentList MixinIdentifier ;
MixinIdentifier:
Identifier
Diferentemente de uma instanciação de gabarito, um corpo de um mixin é avaliado dentro do escopo onde o mixin aparece, não onde a declaração do gabarito está definida. Isso é anáçogo à recortar e colar o corpo do gabarito no lugar do mixin. Isso é útil para injetar código parametrizado, bem como para crear funções aninhadas gabaritadas, que não são possíveis com instanciações de gabaritos.
template Foo()Mixins podem ser parametrizados:
{
int x = 5;
}
mixin Foo;
struct Bar
{
mixin Foo;
}
void test()
{
printf("x = %d\n", x); // imprime 5
{ Bar b;
int x = 3;
printf("b.x = %d\n", b.x); // imprime 5
printf("x = %d\n", x); // imprime 3
{
mixin Foo;
printf("x = %d\n", x); // imprime 5
x = 4;
printf("x = %d\n", x); // imprime 4
}
printf("x = %d\n", x); // imprime 3
}
printf("x = %d\n", x); // imprime 5
}
template Foo(T)Mixins podem adicionar funções virtuais à uma classe:
{
T x = 5;
}
mixin Foo!(int); // cria x de tipo int
template Foo()Mixins são avaliados no escopo onde aparecem, não no escopo da declaração do gabarito:
{
void func() { printf("Foo.func()\n"); }
}
class Bar
{
mixin Foo;
}
class Code : Bar
{
void func() { printf("Code.func()\n"); }
}
void test()
{
Bar b = new Bar();
b.func(); // chama Foo.func()
b = new Code();
b.func(); // chama Code.func()
}
int y = 3;Mixins podem parametrizar simbolos usando parametros apelido:
template Foo()
{
int abc() { return y; }
}
void test()
{
int y = 8;
mixin Foo; // y local é escolhido, não o y global
assert(abc() == 8);
}
template Foo(alias b)Esse exemplo usa um mixin para implementar um dispositivo Duff's genérico para uma instrução arbitrária (nesse caso, a instrução arbitraria está em negrito). Uma função aninhada é gerada, bem como um delegado literal, estes podem ser tornados inline pelo compilador:
{
int abc() { return b; }
}
void test()
{
int y = 8;
mixin Foo!(y);
assert(abc() == 8);
}
template duffs_device(alias id1, alias id2, alias s)
{
void duff_loop()
{
if (id1 < id2)
{
typeof(id1) n = (id2 - id1 + 7) / 8;
switch ((id2 - id1) % 8)
{
case 0: do { s();
case 7: s();
case 6: s();
case 5: s();
case 4: s();
case 3: s();
case 2: s();
case 1: s();
} while (--n > 0);
}
}
}
}
void foo() { printf("foo\n"); }
void test()
{
int i = 1;
int j = 11;
mixin duffs_device!(i, j, delegate { foo(); } );
duff_loop(); // executa foo() 10 vezes
}
Escopo do Mixin
As declarações em um mixin são 'importadas" no escopo envolvendo-o. Se o nome de uma declaraç~´ao em um mixin é o mesmo de uma declaração no escopo envolvendo-o, a declaração envolvendo anula a do mixin:int x = 3;Se dois mixins diferentes ão colocados no mesmo escopo, e cada um define uma declaração com o mesmo nome, há um erro de ambigüidade quando a declaração é referenciada:
template Foo()
{
int x = 5;
int y = 5;
}
mixin Foo;
int y = 3;
void test()
{
printf("x = %d\n", x); // imprime 3
printf("y = %d\n", y); // imprime 3
}
template Foo()Se um mixin tem um MixinIdentifier, ele pode ser usado para diferenciar:
{
int x = 5;
}
template Bar()
{
int x = 4;
}
mixin Foo;
mixin Bar;
void test()
{
printf("x = %d\n", x); // erro, x é ambiguo
}
int x = 6;Um mixin tem seu próprio escopo, mesmo se uma declaração é anulada pela incluindo:
template Foo()
{
int x = 5;
int y = 7;
}
template Bar()
{
int x = 4;
}
mixin Foo F;
mixin Bar B;
void test()
{
printf("y = %d\n", y); // imprime 7
printf("x = %d\n", x); // imprime 6
printf("F.x = %d\n", F.x); // imprime 5
printf("B.x = %d\n", B.x); // imprime 4
}
int x = 4;
template Foo()
{
int x = 5;
int bar() { return x; }
}
mixin Foo;
void test()
{
printf("x = %d\n", x); // imprime 4
printf("bar() = %d\n", bar()); // imprime 5
}