Zunächst stellt sich die Frage, welchen spezifischen Nutzen die Betrachtung von Monaden innerhalb der verschiedenen Programmiersprachen besitzt und in welchen Sprachen Monaden verwendet werden können. Bei der asynchronen Programmierung hat sich herausgestellt, dass ein bestimmtes Problem durch Monaden gelöst werden kann. Anhand von drei Sprachen soll herausgestellt werden, welche Vor- und Nachteile Implementierungen von Monaden in diesen Sprachen haben.
Was sind asynchrone Systeme? Systeme, die Funktionen aufrufen, die einen Callback als Parameter bekommen, die dann bei erfolgreicher Ausführung aufgerufen werden. Solche Systeme gibt es dort, wo der Programmieraufwand für Threading teuer ist, beispielsweise in systemnahen Sprachen oder singlethreaded Umgebungen, wie Javascript, und trotzdem eine hohe Concurrency erreicht werden soll. Ein aktuelles Beispiel ist Node.js, wo Programme aus vielen verschachtelten Callback-Handlern bestehen. Für diese Callback Handler gilt, dass sie nie auf irgend etwas warten sollen, niemals blockieren sollen und generell schnell zurückkehren sollen. Oft werden auch Events oder Nachrichten transportiert.
Qt ist ein Framework für C++, mit einer Netzwerk API, in der die Requests asynchron bearbeitet werden. Requests können verbunden werden, indem im Callback-Handler ein neuer Request gestartet wird. Wie kann in so einem System ein komplexer Algorithmus implementiert werden, der aus vielen unterschiedlichen Requests, teilweise sogar in Rekursion, besteht?
Der traditionelle Weg scheidet fast aus, da die Komplexität schon mit wenigen Requests unübersichtlich wird. Alternativ gibt es die Möglichkeit, in C++ synchron auf die Antwort zu warten, was aber einige negative Effekte hat. Beispielsweise kann dann nur noch ein Request gleichzeitig ausgeführt werden.
Synchrone Algorithmen haben den Vorteil, dass bekannte Kontrollstrukturen vorhanden sind, mit denen sich der Programmfluss beeinflussen lässt. Beispiele dafür sind Rekursionen und Schleifen. Außerdem gibt es lokale Variablen mit einem festen Scope, der eine begrenzte Sichtbarkeit erlaubt. In asynchronen Algorithmen gibt es weder Rekursion noch Schleifen, noch lokale Variablen.
Gibt es eine Alternative, in der Algorithmus quasi-synchron beschrieben wird, aber dennoch asynchron ausgeführt wird? Monaden könnten hier in diesem Fall der Schlüssel sein.
In Software-Systemen, in denen Exceptions entweder nicht benutzt werden oder in denen es keine gibt, müssen eventuelle Fehler in einer Funktion zur aufrufenden Funktion weitergereicht werden. Oft geschieht dies mit Rückgabewerten, die einen Fehler symbolisieren. Und oft gibt es viele gleichartige Funktionen in so einem System.
In einem Beispielsystem gibt es Funktion dieser Art:
1 2 | bool func1(....);
bool func2(....);
|
Werden diese beiden Funktionen komponiert, müssen die Fehlerfälle dieser beiden Funktionen abgefangen werden und wir benötigen deshalb folgendes Konstrukt:
1 2 3 4 5 6 | if (!func1(...)) {
return false;
}
if (!func2(...)) {
return false;
}
|
Gibt es eine Möglichkeit, auch ohne Exceptions die Implementierung von der Fehlerbehandlung zu trennen?