burli hat geschrieben: ↑Sonntag 11. September 2022, 09:19
Sorry, aber das ist völliger Käse.
Starke Worte fuer jemanden, der offensichtlich keine Ahnung hat, wie andere Sprachen Exceptions handhaben.
Aus einer Funktion wird nicht einfach heraus gesprungen wie bei einer Exception. Es gibt immer einen "geordneten Rückzug", soll heißen, ein Ausdruck liefert immer ein Ergebnis zurück. Entweder einen gültigen Wert oder einen Error Type, und zwar immer eingepackt in einem Result Type.
So funktionieren Exceptions in C++ - der Sprache, die hier in Bezug auf das Einsatzgebiet am relevantesten ist - auch schlicht nicht. Denn dort werden alle zum Zeitpunkt der Ausloesung der Ausnahme erzeugten frame-lokalen Variablen destruiert. Dieses Verhalten macht man sich unter anderem in dem RAII-Pattern zu Nutze, bei dem Resourcen trotz Ausnahmen (oder auch nur early returns, aber das ist in diesem Zusammenhang nicht unterscheidbar) wieder freigegeben werden. C kann das (ohne Erweiterungen, GCC hat da was) nicht, und entsprechend finden sich da goto-basierte Pattern, wie zb im Linux-Kernel allueberall:
https://github.com/torvalds/linux/blob/ ... ack.c#L264 - durch Labels definiert man haendisch, welche Resourcen freigegeben werden muessen, wenn man ab einer bestimmten Stelle in einen Fehler laeuft. Und auf dieses Verhalten bezog sich meine Aussage. Das ganze kaskadiert natuerlich so lange, bis ein Handler gefunden wird, oder das Programm (ich denke mal von der crt) beendet wird.
Und ein solches Verhalten zeigt auch Rust, wenn man da den Drop-Trait nutzt. Freigabe trivialen Zustands ist natuerlich auch in C++ und C durch einfaches rueckbauen des Stacks gegeben.
Womit wir bei der Frage waeren, wie anders denn Exceptions vs einem Result-Typen sind. Und da ist die Antwort auch nicht so glasklar, wie du das hier behauptest. Typtheoretisch kann man Exceptions genauso als Summentyp aus der Menge der moeglichen Exceptions plus der Menge der moeglichen "normalen" Return-Werte betrachten. Was durch den algebraischen Typ Result in Rust abgebildet wird. Die Details dessen, wie denn nun genau Exceptions abgearbeitet werden, oder in Rust die Behandlung des Result-Typen erzwungen wird, ist fuer eine Frage danach, ob das nun goto sei oder nicht, irrelevant.
Um das Beispiel aus dem Video aufzugreifen: die num_parse() Funktion würde in Python entweder eine Zahl zurückgeben oder mit eine Exception beendet. Man springt also quasi mit einem Goto aus der Funktion an einen vorher definierten Punkt.
Wie ich dargelegt habe, ist dieses Verstaendnis im Kontext von anderen, statisch typisierten Sprachen ohne garbage collection, falsch. Was du beschreibst ist ein longjump, und auch wenn ich weiss, dass es den gibt, habe ich noch nie das Beduerfnis gehabt, ihn zu benutzen. Das sieht ein bisschen anders aus bei Sprachen wie Python oder Java. Letzteres kennt mit "checked Exceptions" einen Mechanismus, der aehnlich wie Rust das bearbeiten einer Ausnahme erzwingt. Das ist aber dermassen nervtoetend, dass selbst die Java runtime eine ganze Reihe von fundamentalen Ausnahmen als RuntimeException erklaert -weil man sonst vor lauter try/catch/rewrapt nichts mehr erkennen kann.
Und genau hier hat Rust etwas neues beigetragen: der ?-Operator. Der nicht syntaktischer Zucker fuer match ist, sondern fuer das try!-Macro, das zwar ein match enthaelt, aber dessen *zentrale* Aufgabe die Anwendung des From-Trait darstellt. Damit erst wird aus einer Muehsahl etwas ertraegliches - das implizite Wandeln von Fehlern aus tieferen Layern in Fehler die auf hoeheren Layern deklariert sind. Das ist toll, weil es an vielen Stellen die Lesbarkeit erhoeht, ohne die Nuetzlichkeit zu sehr einzuschraenken. Meistens. Aber eben nicht immer.
Denn Java und Python beherrschen hier einen Trick, den Rust nicht beherrscht: weil sie durch GC nicht damit belastet sind, schon im vorneherein Platz fuer eine ganze Kaskade von Fehlern zu reservieren, die beliebig tief sein kann, koennen sie eine Kette von Exceptions erzeugen, die einem eben nicht nur auf einer oberen Anwendungsebene sagt "SQL Connection failed", sondern auch noch die urspruengliche Exception mitliefert, die zeigt, dass es ein Netzwerkfehler war, oder ein Authentifizierungsfehler, oder was auch immer. Da sieht es mit Rust dann oede aus, und darauf hat sich auch Sirius3 bezogen, wenn er sagt, dass Rust etwas verschleiert.
Wir sind hier also mal wieder bei einer Frage der Abwaegung. Wenn dir Rust mehr zusagt, benutz es halt. Aber das es einen magischen Trick gefunden haette, Fehlerbehandlung gleichzeitig robuster und unobtrusiv gemacht zu haben, ist halt ... Kaese.
Und bitte nicht die Begriffe "Expression" und "Exception" verwechseln. Auch wenn sie ähnlich klingen haben sie nichts miteinander zu tun.
Puh. Haette ich das mal zu Zeiten meiner Diplomarbeit zur multi-Level-Typsystemen in funktionalen Sprachen gewusst, ich es waere noch mehr eine 1 geworden.