diff --git a/blog/1970_01_01-rust-vs-cpp-1/images/rust_vs_cpp.png b/blog/1970_01_01-rust-vs-cpp-1/images/rust_vs_cpp.png new file mode 100644 index 0000000..fd1eb67 Binary files /dev/null and b/blog/1970_01_01-rust-vs-cpp-1/images/rust_vs_cpp.png differ diff --git a/blog/1970_01_01-rust-vs-cpp-1/index.mdx b/blog/1970_01_01-rust-vs-cpp-1/index.mdx new file mode 100644 index 0000000..aff3dc3 --- /dev/null +++ b/blog/1970_01_01-rust-vs-cpp-1/index.mdx @@ -0,0 +1,219 @@ +--- +title: "Rust vs C++" +description: "Rust trifft auf modernes C++: Ein fairer Vergleich einiger Sprachfeatures" +authors: + - oliverwith +tags: [rust, c++] +image: ./images/rust_vs_cpp.png +--- + + + +# Rust trifft auf modernes C++ + +*Oder: Wie zwei Entwickler entdecken, dass sie mehr gemeinsam haben als gedacht* + +Es ist Montagnachmittag in der Cafeteria. Sarah, frisch von einem Rust-Projekt zurück, trifft auf Marco, der gerade sein Legacy-Projekt auf C++20 portiert hat. Beide sind in bester Diskutierlaune. + +{/* truncate */} +--- + +## Der Ternary-Twist + +**Marco:** "Rust hat nicht mal einen Ternary-Operator! Den hat sogar C!" + +**Sarah:** "Brauchen wir auch nicht." + +```rust +// Rust: if ist eine Expression +let timeout = if temperature > 150 { 5000 } else { 100 }; +``` + +**Marco:** "Okay, schön. Wir haben das aber kürzer:" + +```cpp +// C++: Der klassische ternary +auto timeout = temperature > 150 ? 5000 : 100; +``` + +**Sarah:** "Und was machst du bei sowas?" + +```rust +let retries = match (production, critical) { + (true, true) => 5, + (true, false) => 3, + (false, _) => 1, +}; +``` + +**Marco:** "Äh... verschachtelte ternaries? Oder ein immediately invoked lambda?" + +```cpp +auto retries = [&]() { + if (production && critical) return 5; + if (production) return 3; + return 1; +}(); +``` + +**Sarah:** "Ein Lambda das du sofort aufrufst? Ernsthaft?" + +**Marco:** "Hey, C++ kann alles! Nur... manchmal etwas umständlich." + +### Fazit + +Der Ternary ist ganz nett für simple Fälle. Aber weil in Rust `if`-Statements Expressions sind, braucht es dieses Extrakonstrukt gar nicht. + +### Exkurs: Expression vs. Statement in Rust + +**Der fundamentale Unterschied:** + +- **Expression** = wird zu einem Wert ausgewertet (z.B. `5 + 3`, `if x { 10 } else { 20 }`) +- **Statement** = führt eine Aktion aus, hat keinen Wert (z.B. `let x = 5;`) + +**Die Rolle des Semikolons:** + +```rust +// Expression: Gibt einen Wert zurück +let x = { + 5 + 3 // Kein Semikolon → Expression, ergibt 8 +}; + +// Statement: Gibt () zurück +let y = { + 5 + 3; // Mit Semikolon → Statement, y hat Typ () +}; +``` + +Salopp gesagt, degradiert in Rust das Semikolon eine Expression zum Statement. Deshalb funktioniert: + +```rust +fn add(a: i32, b: i32) -> i32 { + a + b // Expression, wird zurückgegeben +} + +fn add(a: i32, b: i32) -> () { + a + b; // Statement, gibt () statt i32 zurück - ist aber höchstwahrscheinlich ein Logikfehler +} +``` + +Das ist auch der Grund, warum `if`, `match`, `loop` und sogar Blöcke `{}` in Rust Werte zurückgeben können – sie sind alle Expressions. In C++ sind das Statements, weshalb man ein Extrakonstrukt wie den ternary operator braucht. + +--- + +## Slices und Ranges – Elegant auf Teilstücke zugreifen + +**Sarah:** "Lass uns mal über Slices reden. Slices sind extrem praktisch, um einen Ausschnitt aus einer Datenstruktur auszuleihen." + +**Marco:** "Wir haben seit C++20 auch Ranges! Endlich lazy evaluation." + +**Sarah:** "Zeig mal." + +### Das Problem: Ein Teilstück eines Arrays verarbeiten + +Szenario: Wir haben einen Container, zum Beispiel einen Vektor mit Zahlen, und wollen nur einen Teil davon verarbeiten ohne eine Kopie des Containers zu erstellen. +Der Verarbeitungsschritt ist im Beispiel alle ungeraden Zahlen zwischen Index 2 und 7 aufsummieren + +### Rust: Slices + +Slices sind ein fix eingebautes Feature des Sprachumfangs von Rust + +```rust +fn main() { + let data = vec![1, 2, 3, 5, 7, 8, 11, 13, 16, 20]; + + // Slice: Nimm Elemente von Index 2 bis 7 (exklusiv) + let slice = &data[2..7]; + + // Summiere ungerade Zahlen + let sum: i32 = slice.iter() + .filter(|&&n| n % 2 != 0) + .sum(); + + println!("Summe der ungeraden: {}", sum); +} +``` + +**Sarah:** "Direkte Syntax: `&data[2..7]`. Fertig." + +### C++: Ranges oder Iteratoren + +```cpp +#include +#include +#include + +int main() { + std::vector data = {1, 2, 3, 5, 7, 8, 11, 13, 16, 20}; + + // Variante 1: Mit ranges (C++20, braucht -std=c++20) + auto slice_ranges = data | std::views::drop(2) | std::views::take(5); + auto odd_ranges = slice_ranges + | std::views::filter([](int n) { return n % 2 != 0; }); + + int sum_ranges = 0; + for (auto n : odd_ranges) { + sum_ranges += n; + } + std::cout << "Summe ungerade (ranges): " << sum_ranges << "\n"; + + // Variante 2: Mit klassischen Iteratoren + auto slice_begin = data.begin() + 2; + auto slice_end = data.begin() + 7; + + int sum_iter = 0; + for (auto it = slice_begin; it != slice_end; ++it) { + if (*it % 2 != 0) { + sum_iter += *it; + } + } + std::cout << "Summe ungerade (iteratoren): " << sum_iter << "\n"; +} +``` + +**Marco:** "Ranges funktionieren... aber ich muss `drop(2)` und `take(5)` kombinieren." + +**Sarah:** "Warum nicht einfach `data[2..7]`?" + +**Marco:** "Das geht nicht. Wir haben keine Slice-Syntax. Dafür kann ich zwischen Ranges und Iteratoren wählen!" + +### Der Unterschied + +**Sarah:** "Der Punkt ist: Slices sind bei Rust von Anfang an eingebaut. Teil der Sprache." + +```rust +// Verschiedene Slice-Notationen +&data[2..7] // Von 2 bis 7 (exklusiv) +&data[2..] // Von 2 bis Ende +&data[..7] // Von Anfang bis 7 (exklusiv) +&data[..] // Alles +``` + +**Marco:** "Bei uns kam das mit C++20 nach. Und es braucht `-std=c++20` als Compiler-Flag." + +**Sarah:** "Und `views::drop(2) | views::take(5)` ist nicht gerade intuitiv." + +**Marco:** "Stimmt. Aber immerhin haben wir's jetzt! Und C++ kann alles... nur manchmal etwas umständlich." + +### Lazy Evaluation + +**Sarah:** "Wenigstens sind beide lazy – kein Zwischenarray wird erstellt." + +**Marco:** "Ja! Das war ein großer Fortschritt. Früher mussten wir alles kopieren." + +**Sarah:** "Okay, C++ Ranges sind definitiv eine Verbesserung." + +### Fazit + +Beide Sprachen haben Konzepte für Teilstücke von Sequenzen: +- **Rust:** Native Slice-Syntax `&data[2..7]`, Teil der Sprache seit Tag 1 +- **C++:** Ranges seit C++20 (braucht `-std=c++20`), oder klassische Iteratoren + +**Der Unterschied:** Rust hat Slices von Grund auf eingebaut mit direkter, intuitiver Syntax. C++ hat Ranges nachgerüstet – funktioniert, aber mit umständlicherer Syntax (`drop`/`take` statt direkter Range-Notation). + +**Für Legacy-Code:** C++ kann auf Iteratoren zurückfallen, die seit Jahrzehnten existieren. + +### Code Samples zu Slices + +- [C++ Beispiel bei godbolt](https://godbolt.org/z/r55oc4dea) +- [Rust Beispiel im rustplayground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=a850df5a96c7391064a781b3514025f5) diff --git a/blog/authors.json b/blog/authors.json index b0b061b..09a1055 100644 --- a/blog/authors.json +++ b/blog/authors.json @@ -33,5 +33,18 @@ "socials": { "github": "wtjerry" } + }, + "oliverwith": { + "name": "Oliver With", + "title": "Senior Software Engineer", + "description": "Oliver With is a Senior Software Engineer and Embedded Software Specialist at bbv Software Services AG. He is enthusiastic about Rust because it is the first language to combine memory safety, performance, and developer experience.", + "url": "https://www.linkedin.com/in/oliver-with/", + "imageURL": "/img/authors/OliverWith.jpg", + "page": true, + "image": "", + "socials": { + "linkedin": "oliver-with", + "github": "quattervals" + } } } diff --git a/blog/tags.yml b/blog/tags.yml index e69de29..4d192d0 100644 --- a/blog/tags.yml +++ b/blog/tags.yml @@ -0,0 +1,23 @@ +kubernetes: + label: Kubernetes + permalink: /kubernetes + +architecture: + label: Architecture + permalink: /architecture + +cloud-native: + label: Cloud Native + permalink: /cloud-native + +well-architected: + label: Well-Architected + permalink: /well-architected + +rust: + label: Rust + permalink: /rust + +c++: + label: C++ + permalink: /cpp diff --git a/package-lock.json b/package-lock.json index ac4254c..b212b59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -211,7 +211,6 @@ "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.46.3.tgz", "integrity": "sha512-hfpCIukPuwkrlwsYfJEWdU5R5bduBHEq2uuPcqmgPgNq5MSjmiNIzRuzxGZZgiBKcre6gZT00DR7G1AFn//wiQ==", "license": "MIT", - "peer": true, "dependencies": { "@algolia/client-common": "5.46.3", "@algolia/requester-browser-xhr": "5.46.3", @@ -350,7 +349,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", @@ -2197,7 +2195,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -2220,7 +2217,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2330,7 +2326,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -2752,7 +2747,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3772,7 +3766,6 @@ "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", "license": "MIT", - "peer": true, "dependencies": { "@docusaurus/core": "3.9.2", "@docusaurus/logger": "3.9.2", @@ -4548,7 +4541,6 @@ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.0.tgz", "integrity": "sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/mdx": "^2.0.0" }, @@ -5036,7 +5028,6 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -5658,7 +5649,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6015,7 +6005,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6101,7 +6090,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -6147,7 +6135,6 @@ "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.46.3.tgz", "integrity": "sha512-n/NdPglzmkcNYZfIT3Fo8pnDR/lKiK1kZ1Yaa315UoLyHymADhWw15+bzN5gBxrCA8KyeNu0JJD6mLtTov43lQ==", "license": "MIT", - "peer": true, "dependencies": { "@algolia/abtesting": "1.12.3", "@algolia/client-abtesting": "5.46.3", @@ -6636,7 +6623,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7649,7 +7635,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7969,7 +7954,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -8379,7 +8363,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -9557,7 +9540,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14148,7 +14130,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14726,7 +14707,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -15630,7 +15610,6 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -16459,7 +16438,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16469,7 +16447,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -16525,7 +16502,6 @@ "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/react": "*" }, @@ -16554,7 +16530,6 @@ "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.12.13", "history": "^4.9.0", @@ -18384,8 +18359,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsyringe": { "version": "4.10.0", @@ -18466,7 +18440,6 @@ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18814,7 +18787,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -19075,7 +19047,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -19666,7 +19637,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/static/img/authors/OliverWith.jpg b/static/img/authors/OliverWith.jpg new file mode 100644 index 0000000..dbe1474 Binary files /dev/null and b/static/img/authors/OliverWith.jpg differ