On peut associer des attributs aux fonctions de plusieurs façon en D. Nous allons jeter un coup d'œil à deux attributs directement intégrés au langage mais aussi à des attributs personnalisés. Les attributs @safe
, @trusted
et @system
ont déjà été mentionnés dans la première partie de la visite.
@property
Une méthode marquée avec l'attribut @property
se comporte comme un membre normal depuis l'extérieur de la classe ou de la structure:
struct Foo
{
@property bar() { return 10; }
@property bar(int x) { writeln(x); }
}
Foo foo;
writeln(foo.bar); // appelle en fait foo.bar()
foo.bar = 10; // appelle foo.bar(10);
@nogc
Quand une fonction est marquée avec l'attribut @nogc
, le compilateur D nous garantit qu'aucune allocation mémoire ne sera faite dans cette fonction. Une fonction @nogc
ne peut appeller que des fonctions @nogc
void foo() @nogc
{
// ERREUR:
auto a = new A;
}
N'importe quelle fonction ou type en D peut être marquée par un attribut personnalisé:
struct Bar { this(int x) {} }
struct Foo
{
@("Hello")
{
@Bar(10) void foo()
{
//...
}
}
}
N'importe quel type, fondamental ou non, peut être associé à une fonction. Dans cet exemple, la fonction foo()
aura les attributs "Hello" (de type string
) et Bar
(de type Bar
et de valeur 10
). Pour accéder à ces attributs, on utilise le trait (une fonctionnalité qui permet de récuper des informations sur notre programme pendant la compilation) intégré au compilateur __traits(getAttributs, Foo)
qui retourne une AliasSeq
.
Les attributs personnalisés permettent d'améliorer la généricité du code en donnant la possibilité de générer le code le plus adapté à l'utilisation de la fonction ou de l'objet, et ce à la compilation.