Skip to content
Zurück zum BlogRust ist kein C++ mit anderer Syntax — die Architektur muss mitwandern
rust cpp architecture migration typestate ownership

Rust ist kein C++ mit anderer Syntax — die Architektur muss mitwandern

14. November 2026~5 min read· Tobias Weiss

Die Uebersetzung von C++-Codebase nach Rust scheitert haeufig nicht an der Syntax, sondern daran, dass die Architektur der Originalcode nicht uebertragbar ist. Drei aktuelle Papers zeigen warum — und wie man es richtig macht: das C-to-Rust Fallacy-Papier (arXiv 2609.25682), die Gap-Taxonomie arXiv 2609.XX und der Typestate-Erfahrungsbericht ("Functional State Machines in Rust", DOI 10.1145/3830438.3830958).

Warum Literal-Translation scheitert: Die Fallacy

Das "C-to-Rust Fallacy: Automatic Refactoring != Memory Safety" Paper arXiv 2609.25682 beweist: Wer C++ 1:1 nach Rust uebersetzt, bleibt mit den Architektur-Problemen des Originals zurueck. Der Grund ist einfach — Memory Safety ist in Rust kein Feature, sondern eine Konsequenz der Architektur.

In C++ drueckt sich die Architektur haeufig in Pointer-Netzwerken aus: std::unique_ptr<Node> hier, std::shared_ptr<Child> da, raw Pointers wo die Performance es verlangt. Diese Struktur ist nicht nur Code, sie ist das implizite Design des Systems. Eine wortgetreue Uebersetzung mit Box<T>, Rc<T>, Arc<T> behaelt die gleiche Architektur — und damit die gleichen Design-Fehler.

Memory Safety durch Architektur, nicht durch Syntax

Rusts Typsystem erzwingt Memory Safety nur, wenn die Architektur entsprechend gestaltet ist. Ownership, Borrowing und Lifetimes sind keine Sprachfeatures, sondern Architektur-Primitive. Eine 1:1-Uebersetzung uebernimmt die C++-Architektur — und damit deren unsichere Annahmen.

Beispiel: Ein C++-Parser der Dokumente als pointer-basierten Baum hierarchien representiert, wird in Rust zu einer Struktur die immer noch auf Lifetimes und Borrows angewiesen ist. Die Loesung: den Baum als enum-basierte State Machine modellieren. Plötzlich werden ungueltige Zustaende nicht runtime geprüft, sondern sind unmoeglich.

Die Gap-Taxonomie: Wo C++ und Rust sich semantisch unterscheiden

"Beyond Compilation: A Taxonomy of Semantic Gaps in C-to-Rust Translation" (2026) kategorisiert die wichtigsten semantischen Unterschiede — und zeigt why eine Uebersetzung immer auch ein Redesign sein muss:

GapC++RustArchitektur-Folge
Pointer AliasingMehrere Pointer auf dieselbe DatenEin Owner, viele BorrowsDatenfluss muss linear werden
Undefined BehaviourUndefiniert bei Overflow, Null-DerefDefiniert oder Compile-ErrorExplicite Fehlerbehandlung
Type Punningreinterpret_castunsafe + invariantsTyp-Sicherheit wird erzwungen
Implicit ConversionsImplizit Integer → FloatExplicite as/FromTyp-Klarheit
Platform Assumptionssizeof(int) variabelPlattform-unabhaengigAbstraktionsschichten

Jede dieser Luecken verlangt eine Anpassung der Datenstrukturen und Algorithmen — nicht nur der Syntax.

Typestate: Architektur sichtbar machen

Der Typestate-Erfahrungsbericht "Functional State Machines in Rust" (DOI 10.1145/3830438.3830958) zeigt, wie Rust Zustandsautomaten als Typen modelliert. Das ist kein akademisches Spiel, sondern Architektur-Dokumentation in Code-Form.

Nehmen wir eine Bestellungs-Verarbeitung:

// Jeder Zustand ist ein eigener Typ
pub struct DraftOrder;
pub struct PaidOrder;
pub struct ShippedOrder;
pub struct CancelledOrder;

// Uebergaenge sind Methoden die *nur* auf bestimmten Typen existieren
impl DraftOrder {
    pub fn pay(self, amount: Currency) -> PaidOrder { /* ... */ }
}

impl PaidOrder {
    pub fn ship(self, tracking: TrackingId) -> ShippedOrder { /* ... */ }
    pub fn cancel(self) -> CancelledOrder { /* ... */ }
}

// ShippedOrder hat KEIN cancel() — der Compiler verbietet es
impl ShippedOrder {
    pub fn track(&self) -> TrackingInfo { /* ... */ }
}

Das eigene Typen fuer jeden Zustand hat drei Vorteile:

  1. Compile-Zeit-Garantie: shipped_order.cancel() ist kein Code den man schreiben kann. Der Fehler wird zur Compile-Zeit gefangen.
  2. Exhaustiveness: Jeder Zustand muss im Code behandelt werden. Ein neuer Zustand zwingt alle Call Sites zur Anpassung.
  3. Architektur-Dokumentation: Die Typen sind die Architektur. Nicht als Diagramm in Confluence, sondern als kompilierbarer Code.

World-Office als Fallstudie: Rust-Fleet

Das World-Office-Projekt hat eine proprietary C++-Codebase (ONLYOFFICE Core: x2t Parser + sdkjs Editing Model) nach Rust portiert. Das Translation-Paradigms-Dokument (World-Office/AGENTS.md) definiert sieben Paradigmen fuer diese Migration:

  1. Sum Types over Virtual Dispatch: enum + match statt Box<dyn Trait>
  2. Ownership: clone-mutate-store: Never borrow across mutation
  3. Fail with Result: Kein Panic in Library-Code
  4. Char-index (Unicode) Semantics: Zeilen- und Zeichen-Offsets richtig
  5. Verify, don't trust: Jede übersetzte Einheit braucht Tests
  6. unsafe is a gate, not a tool: Mit Invarianten und Tests
  7. Idiomatic Rust, not transliteration: cargo clippy clean ist Pflicht

Das Ergebnis: Eine Codebase die nicht nur memory-safe ist, sondern auch durch ihre Architektur beweisbar korrekt funktioniert.

Im World-Office Rust-Fleet wird Typestate extensively genutzt — nicht nur fuer einfache State Machines, sondern fuer ganze Dokument-Modelle. Ein Dokument kann plötzlich nicht in einem "halben Zustand" sein, weil dieser Zustand gar nicht im Typsystem existiert.

Die Marche: Wohin die Forschung geht

Die aktuelle Forschung zeigt einen Trend von "Translation" zu "Transmutation":

  • Phase 1 — Translation Tools: TRACTOR (arXiv 2609.25121) als Benchmark fuer C-to-Rust Translators
  • Phase 2 — Fallacy Erkennung: Automatische Erkennung von semantischen Gaps (arXiv 2609.25682)
  • Phase 3 — Provable Rust: KVerus (DOI 10.1145/3832783.3834503) und VerusSeek fuer formale Verifikation von Rust-Code

Das Ziel ist klar: Nicht nur von C++ nach Rust uebersetzen, sondern von einer unsicheren zu einer beweisbar sicheren Architektur wandern.

Fazit: Architektur vor Syntax

Rust ist kein C++ mit anderer Syntax. Rust ist eine Sprache in der Architektur sichtbar und erzwingbar ist. Wer nur die Syntax uebersetzt, verpasst den Punkt. Wer die Architektur anpasst, gewinnt nicht nur Memory Safety, sondern auch ein System das leichter zu verstehen, zu testen und zu warten ist.

Der erste Schritt ist das Eingeständnis: Dein C++-Code hat wahrscheinlich eine Architektur die nicht 1:1 auf Rust uebertragbar ist. Der zweite Schritt ist die Akzeptanz: Das ist gut so. Der dritte Schritt ist der Entschluss: Nutze die Gelegenheit, die Architektur zu verbessern.

Weiterlesen

Ins Thema einsteigen

Fang klein an, aber fang richtig an:

  1. Lies die Fallacy: arXiv 2609.25682 zeigt warum naives Uebersetzen nicht funktioniert
  2. Verstehe die gaps: Die Gap-Taxonomie hilft Dir die kritischen Unterschiede C++ ↔ Rust zu erkennen
  3. Probiere Typestate: Implementiere eine einfache State Machine mit Typestate und erlebe die Compile-Zeit-Garantien selbst
  4. Mache Modul 25: Migration einer realen C++-Komponente nach Rust
  5. Nutze TRACTOR: Das arXiv 2609.25121 Tool als Benchmark fuer Deine eigenen Translation-Experimente

Verwandte Artikel

This site uses essential cookies for Stripe payments. No tracking cookies.