robust-co.de

– Starke Typen

Starke Typen

18.04.2014

Starke statische Typ-Systeme können die robuste Programmierung unterstützen.

Keine Statischen Typen

Fangen wir mit einer einfachen Funktion an, die wir zuerst in JavaScript schreiben:

function reziprok(x) {
    return 1/x;
}

Diese Funktion ist nicht sonderlich robust. Was passiert zum Beispiel bei folgendem Aufruf:

reziprok("hallo");

Oder bei:

reziprok();

Die Funktion kann mit jedem Typ aufgerufen werden. Aber der Kehrwert kann nur von einem numerischen Typ, der nicht 0 ist, berechnet werden.

Um das sicherzustellen, muss das Argument explizit geprüft werden:

function reziprok(x) {
    if (typeof(x) == "Number") {
        if (x) {
            return 1/x;
        } else console.log("divide by zero");
    } else console.log("argument is not a number");
}

Statische Typen

In Java wirkt die Methode etwas aufgeräumter. Hier kann der Compiler erzwingen, dass die Methode nur mit Zahlen aufgerufen wird.

public class MyMath {
    public static double reziprok(double x) {
        if (x != 0) {
            return 1/x;
        } else System.err.println("divide by zero");
        return Double.NaN;
    }
}

Aber immer noch muss explizit auf 0 geprüft werden.

Ärgerlicher ist das bei Objekten, die null sein können. Hier muss in Java explizit getestet werden, ob das Objekt wirklich da ist. Ansonsten winkt die NullPointerException, die in der Comunity schon liebevoll NPE abegkürzt wird.

public class MyCommon {
    public static boolean areEqual(Object a, Object b) {
        if (a != null) {
            return a.equals(b);
        } else return b == null;
    }
}

Noch mächtigere Typ-Systeme

In Sprachen wie Haskell gibt es zumindest das letzte Problem nicht. Wenn der Parameter vom Typ Customer ist, dann muss die Funktion auch immer mit einem Customer aufgerufen werden. null ist kein Customer.

Wenn der Customer optional ist, dann ist der Typ Maybe Customer, das entweder Just Customer oder Nothing ist.

Dies erleichtert die robuste Programmierung, da auch hier der Compiler sicherstellt, dass die Funktion nur mit passenden Typen aufgerufen wird. Ein eigener Test im Code kann damit entfallen.

Soweit ich weiss, ist aber selbst Haskell nicht mächtig genug, wie wir an der Reziprok-Funktion sehen. Wenn ich über den Typ sicherstellen kann, dass x niemals 0 ist, dann brauche ich gar keine Tests im Code.

Durch einen solchen Typ würde der Code lesbarer, da die Signatur schon ausdrückt, wie die Methode aufgerufen werden kann. Im Ideal-Fall würde alles, was in Sprachen wie Eiffel über Preconditions abgebildet wird, schon durch den Typ beschrieben.

Der Typ würde zu einem Ausdruck mutieren, der vom Compiler ausgewertet werden muss, um sicherzustellen, dass ein Aufruf legal ist.

Aber so weit sind wir leider noch nicht.

Zusammenfassung

Typen unterstützen uns bei der robusten Programmierung. Ein Typ schränkt die Werte ein, mit denen eine Funktion aufgerufen werden kann. Dadurch reduziert sich der Test-Aufwand innerhalb der Methode.


Kommentare

Möchten Sie einen Beitrag korrigieren, ergänzen oder kommentieren? Senden Sie mir eine E-Mail an timm@robust-co.de. Interessante Beiträge veröffentliche ich gerne auf dieser Seite.