Contract Programming (dt.: vertragsbasierte Programmierung) in D umfasst einen Satz von Sprachkonstrukten, die die Quellcodequalität durch bestimmte Prüfroutinen (sog. Contracts) erhöhen und korrektes Verhalten sicherstellen sollen.
Contracts stehen nur im Debug-Modus zur Verfügung und werden im Release-Modus nicht ausgeführt. Deshalb sollten sie nicht für die Überprüfung von Benutzereingaben eingesetzt werden.
assertDer assert(...)-Ausdruck bietet die einfachste Form
des Contract Programming und prüft ob eine bestimmte
Bedingung eingehalten wird, anderenfalls bricht das
Programm ab.
assert(sqrt(4) == 2);
// optionale benutzerdefinierte Fehlernachricht
assert(sqrt(16) == 4, "sqrt is broken!");
in und out erlauben formalisierte Contracts für
Eingangsparameter und Rückgabewerte von Funktionen.
long square_root(long x)
in {
assert(x >= 0);
} out (result) {
assert((result * result) <= x
&& (result+1) * (result+1) > x);
} body {
return cast(long)std.math.sqrt(cast(real)x);
}
Der Inhalt des in-Blocks könnte auch im Rumpf der Funktion
stehen, auf diese Art wird aber die Intention viel klarer.
Im out-Block der Funktion kann der Rückgabewert mit
out(result) erfasst und entsprechend geprüft werden.
invariant() ist eine spezielle Memberfunktion von struct-
und class-Typen, der die Überprüfung des Objektzustands
während dessen gesamter Lebenszeit erlaubt.
invariant() wird zu folgenden Zeitpunkten ausgeführt:
Da alle Contracts im Release-Build entfernt werden, sollten
Benutzereingaben nicht mit Contracts überprüft werden.
Darüber hinaus können asserts weiterhin in nothrow-Funktionen
verwendet werden, da diese fatale Error werfen.
Die Laufzeitentsprechung zu assert ist std.exception.enforce,
die auffangbare Exceptions wirft.