- Der Autor, der seit mehr als 20 Jahren C++ nutzt, schildert anhand eines Vortrags von Matt Godbolt, was ihn dazu brachte, die Stärken von Rust neu zu entdecken
- In C++ werden Fehler durch Typverwechslungen vom Compiler oft nicht zuverlässig erkannt, während Rust sie zur Compile-Zeit konsequent verhindert
- Rust ist nicht nur bei der Speichersicherheit stark, sondern auch so entworfen, dass Missbrauch von APIs erschwert wird
- Besonders bei der Verarbeitung von Laufzeiteingaben zwingt Rust dazu, Fehler explizit zu behandeln, was Risiken reduziert
- Am Ende zeigt sich, dass Sprachdesign ein mächtiges Werkzeug sein kann, um Entwicklerfehler zu verhindern
Einleitung
- Matt Godbolts Vortrag "Correct by Construction" beleuchtet Probleme im API-Design von C++ und passt damit gut zur Philosophie von Rust
- Der Vortrag ist ein guter Einstieg, um die Stärken von Rust zu verstehen
What's in a type — die Grenzen von C++
- Eine Funktionssignatur wie
void sendOrder(const char *symbol, bool buy, int quantity, double price) ist sehr fehleranfällig
- Wenn nur Grundtypen wie
bool, int und double verwendet werden, warnt der Compiler nicht, selbst wenn Typen vertauscht werden
- Typ-Aliasse wie
using Price = double bieten keine echte Typtrennung
- Erst mit Klassen und
explicit-Konstruktoren für Quantity und Price kann der Compiler einige Fehler erkennen, aber:
- Negative Werte sind weiterhin erlaubt, und das wird erst zur Laufzeit zum Problem
- Mit
static_assert und Templates lassen sich Compile-Time-Prüfungen erzwingen
- Trotzdem können Laufzeitkonvertierungen wie
atoi weiterhin Integer-Überläufe verursachen, ohne dass der Compiler sie erkennt
Was macht Rust anders?
- Selbst bei derselben Funktionsdefinition meldet Rust Typinkompatibilitäten eindeutig bereits beim Kompilieren als Fehler
- Neue Typdefinitionen wie
struct Price(pub f64); struct Quantity(pub u64); sind ebenfalls einfach, und negative Eingaben werden ganz natürlich abgefangen
- Bei Laufzeit-Stringkonvertierungen wie
"string".parse::<u64>() ist explizite Fehlerbehandlung erforderlich
- Wenn man mit
.expect() das Unwrapping eines Werts erzwingt, kommt es zwar zu einem Laufzeitabsturz, doch das ist laut Text immer noch besser als stille Fehler in C++
Fazit
- Rust schützt Entwickler weit über reine Speichersicherheit hinaus durch Verhinderung von API-Missbrauch, Compile-Time-Prüfungen und ein klares Typsystem
- Das zeigt, dass die Kraft des Sprachdesigns Entwicklerfehler schon im Vorfeld verhindern kann
- Rust-Einsteiger können zunächst damit kämpfen, sich mit dem Borrow Checker auseinanderzusetzen, doch das legt sich mit der Zeit
- C++ hat sich historisch stark weiterentwickelt, doch es zeigt sich weiterhin, dass es nur schwer dieselbe grundlegende Sicherheit und Klarheit wie Rust bieten kann
Referenz
4 Kommentare
Die meisten Punkte, die als Nachteile von C++ angeführt werden, scheinen größtenteils Inhalte zu sein, die wegen der Kompatibilität mit C beibehalten werden. Lässt sich C-Kompatibilität aufgeben und die Sprache so ändern, dass man damit entwickeln kann?
Es wäre besser gewesen, wenn
unsafenicht bereitgestellt worden wäre.Die grundlegende Sprache = Rust
Hacker-News-Kommentare
Der größte Vorteil von Rust ist die vereinheitlichte Fehlerweitergabe über den einheitlichen Typ
Result. Es ist attraktiv, dass man sich nicht um Ausnahmebehandlung oder verschiedene Arten der Fehlerrückgabe kümmern muss.?-Kurzschreibweise und der funktionalen Schnittstelle vonResultmacht Fehlerbehandlung Spaß und ist leicht zu handhaben.Es gibt viel Unzufriedenheit mit C++. Besonders problematisch ist, dass man sich viele Regeln merken muss und der Code schon bei einem einzigen Fehler anfällig werden kann.
Der aktuell geschriebene C++-Code ähnelt Rust. Es werden explizite und starke Typen sowie eine klare Verwaltung der Lebensdauer verwendet.
Das Problem impliziter Konvertierungen in C++ ist eher ein Bibliotheks- als ein Sprachproblem.
In Rust ist es unpraktisch,
Args-/Options-Structs zu verwenden, weil es keine Keyword-Argumente oder benannten Tupel gibt.Die Option
-Wconversionkann bestimmte Konvertierungsprobleme erkennen, gilt aber nicht für alle Fälle.Ein weiterer Vorteil von Rust ist, dass es keine impliziten numerischen Konvertierungen gibt. In C++ sollte man statt
atoibesser die Konvertierungsfunktionen der STL verwenden.Funktionen ähnlich wie SQL-Constraints oder benutzerdefinierte Typen und Validatoren von pydantic gibt es in Rust oder Golang bislang noch nicht.
Wer sich für den Programmier-Podcast „Two's Complement“ von Matt und Ben Rady interessiert, sollte einmal reinhören.