La programmation par contrats en D est un ensemble de fonctionnalités qui permettent d'améliorer la qualité du code en implémentant des tests pour s'assurer que le code se comporte comme on le souhaite. Les contrats ne sont disponibles qu'en mode debug et ne seront pas exécutés en mode release. Ils ne doivent donc pas être utilisés pour valider une entrée de l'utilisateur.
assert
La forme la plus simple de programmation par contrats en D est l'utilisation d'expressions assert(...)
qui vérifient qu'une certaine condition est remplie, et déclenchent une AssertionError
dans le cas contraire:
assert(sqrt(4) == 2);
// on peut associer un message d'erreur à une expression assert
assert(sqrt(16) == 4, "sqrt ne fonctionne pas !");
in
et out
permettent de formaliser des contrats pour vérifier les entrées et/ou les sorties de fonctions.
long racineCarree(long x)
in
{
// On vérifie que l'argument est valide
assert(x >= 0);
}
out
{
// On vérifie que notre résultat est cohérent
assert((result*result) <= x
&& (result+1) * (result+1) > x);
}
body
{
return cast(long)std.math.sqrt(cast(real)x);
}
Le contenu du bloc in
pourrait aussi être placé au début du corps de la fonction, mais c'est bien plus clair de cette façon. Le bloc out
peut capturer la valeur de la retour de la fonction en utilisant la syntaxe out(result)
.
invariant()
est une méthode spéciale des struct
et des class
qui permet d'assurer l'intégrité d'un objet au cours de son existence.
Si tous les contrats sont retirés dans une version release
, il faut faire attention à ne pas vérifier les données entrées par l'utilisateur dans les contrats.
À noter également qu'il est possible de mettre des expressions assert
dans des fonctions nothrow
puisqu'elles déclenchent des Error
s et non des Exception
s. L'équivalent de assert
à l'exécution est la fonction std.exception.enforce
, qui déclenche des Exception
s que l'ont peut intercepter et gérer.