Mijn roestige kerst: hoe Rust een plek verdiende naast C++, Java, Python en Go (en me liet ruziën met traits) :christmas_tree::crab:



Crowds of fun-seekers exploring a city on foot, "

Arjan Franzen

6 januari 2026

image (1).webp

Om de zoveel jaar verdient een nieuwe taal een vaste plek in je gereedschapskist.
Niet omdat hij in de mode is.
Niet omdat het internet zegt dat het moet.

Maar omdat je op enig moment beseft:

“Dit lost problemen op die ik al heb — ook al irriteert het me eerst.”

Deze kerst kwam Rust voor mij op dat lijstje.

Het vertrekpunt

Mijn achtergrond is behoorlijk breed:

  • zo'n 10 jaar C++ (systemen, performance, RAII, undefined behaviour als doorleefde ervaring)

  • veel Java (enterprise, schaal, systemen die lang meegaan)

  • ruim voldoende Python (lijmwerk, denksnelheid, experimenteren)

  • wat Go (services, pragmatisme — de minste van de vier)

Rust cirkelde al jaren om me heen. Conceptueel bewonderde ik het, maar net als veel C++-developers had ik de gebruikelijke gedachte:

“Ziet er mooi uit, maar ik weet zelf ook wel hoe je dit veilig doet.”

Dus deze kerst ben ik gestopt met theoretiseren en gewoon gaan bouwen.

Wat ik verwachtte versus wat er gebeurde

Wat ik verwachtte:

  • een steile leercurve

  • veel compilerfouten

  • een hoop slimme ideeën verpakt in wrijving

Wat er werkelijk gebeurde:

  • een steile leercurve

  • veel compilerfouten

  • …en een groeiend vermoeden dat de compiler meestal gelijk had

Een voorbeeld van vroeg in het proces:

Het voelde als een uitgesproken code reviewer die al mijn oude fouten al eens had gezien.

1let a = String::from("hello");    
2let b = a;    
3// println!("{a}"); // ❌ compile error
4

In C++ zou dit compileren en later ontploffen.

Rust zegt gewoon “nee” — meteen, en met goede reden.

Rust voelde niet als een nieuw paradigma.

Ownership en borrowing: minder leugens, meer eerlijkheid

De grote omslag zat in ownership en borrowing.

In het begin voelt het beperkend.

Daarna voelt het ronduit onaangenaam.

En dan — langzaam — voelt het eerlijk.

1fn len(s: &String) -> usize {
2    s.len()
3}
4let s = String::from("hello");
5let n = len(&s);
6println!("{s}"); // ✅ still valid

Geen achteloze aliasing meer.

Geen “deze referentie zal wel goed zijn” meer.

Geen mentale boekhouding meer over wie wat wanneer vrijgeeft.

Vanuit C++ voelde dit niet als macht inleveren — het voelde als het formaliseren van discipline die ik toch al handmatig probeerde toe te passen.

Foutafhandeling zonder drama

Rusts foutmodel klikte sneller dan verwacht.

  • fouten zijn data

  • falen is expliciet

  • je control flow is zichtbaar

1fn read_config() -> Result<String, std::io::Error> {
2    let content = std::fs::read_to_string("config.toml")?;
3    Ok(content)
4}

Alleen de ?-operator al verdient een klein altaartje.

Hij leest precies zoals hij werkt:

“Gaat dit mis, stop dan hier — netjes.”

Na jaren C++-excepties en Go's if err != nil voelde dit als de volwassen versie van allebei.

En toen… kwamen de numerieke traits

Ergens tijdens de kerst maakte ik de klassieke fout.

Ik wilde een simpele functie schrijven die “gewoon werkt voor getallen”.

Mijn Python-brein zei:

1def add(a, b):
2    return a + b

Rust antwoordde:

1fn add<T>(a: T, b: T) -> T {
2    a + b
3}
4// ❌ nope

Dus gaf ik op wat Rust wilde weten:

1use std::ops::Add;
2fn add<T: Add<Output = T>>(a: T, b: T) -> T {
3    a + b
4}

Vervolgens wilde ik types mengen.

1add(1i32, 2.0f64); // ❌ still nope
2

Op een gegeven moment zat ik naar trait bounds te staren met de gedachte:

“Ik heb template metaprogramming in C++ geschreven.

Waarom is dit lastiger dan ik verwachtte?”

Hier komt die Rust-meme over getallen pijnlijk dichtbij.

Wil je “getallen” in Rust, dan krijg je geen gratis abstractie.

Je krijgt:

  • traits

  • bounds

  • associated types

  • crates zoals num

En het sluipende besef dat dit met opzet zo is.

Het ongemakkelijke inzicht

En toen viel het kwartje.

Rust is niet slecht in numerieke abstractie.

Rust weigert te liegen.

Python zegt:

“Ik zoek het wel uit tijdens runtime.”

Rust zegt:

“Zeg me precies wat je bedoelt, of het gaat niet de deur uit.”

Dus schrijf je uiteindelijk:

1fn add_as_f64<A: Into<f64>, B: Into<f64>>(a: A, b: B) -> f64 {
2    a.into() + b.into()
3}

Ja, dat is explicieter.

Ja, dat is meer wrijving.

Maar het betekent ook:

  • geen stilzwijgende afkapping

  • geen impliciete verbreding

  • geen platformafhankelijk gedrag

  • geen rekenfouten die “in de tests werkten maar niet in productie”

Op dat moment genoot ik niet van dat inzicht.

Maar ik had er wel respect voor.

Undefined behaviour, nu met hekken eromheen

Na genoeg jaren C++ ben je niet meer bang voor crashes.

Je bent bang voor de bugs die alleen in productie opduiken.

Rusts houding tegenover UB is verfrissend recht voor zijn raap:

1unsafe {
2    let p = 0xdeadbeef as *const i32;
3    println!("{}", *p); // UB lives here, clearly marked
4}

Ja, UB bestaat.

Nee, je krijgt het niet per ongeluk.

Wil je het, dan moet je er expliciet voor kiezen.

Dat verandert hoe je over grenzen denkt — en over vertrouwen.

Async zonder garbage collector (nog altijd licht magisch)

Async Rust verdient een eigen artikel, maar in het kort:

1async fn fetch(url: &str) -> Result<String, reqwest::Error> {
2    let body = reqwest::get(url).await?.text().await?;
3    Ok(body)
4}
  • async/await zonder garbage collector

  • futures als expliciete toestandsmachines

  • geen runtime die geheugenkosten voor je verstopt

Ja, de borrow checker wordt hier luidruchtiger.

Ja, je moet soms je code herschikken.

Maar het resultaat is voorspelbare performance met veiligheid al bij het compileren, en dat blijft zeldzaam.

Van kerstexperiment naar echt werk

Het echte signaal was niet intellectueel.

Dit bleef geen vakantie-experiment.

Nog voor de kerst voorbij was, gebruikte ik Rust al in een project van ZEN Software — niet als herschrijving voor de lol, maar precies daar waar Rusts sterke punten passen:

  • correctheid

  • performance

  • onderhoudbaarheid op lange termijn

Dat is meestal het moment waarop een taal ophoudt interessant te zijn en nuttig wordt.

Waar Rust nu in mijn gereedschapskist zit

Ik denk niet in vervangingen.

Voor mij ziet het er nu zo uit:

  1. Java → stabiliteit, schaal, voorspelbaarheid

  2. Python → denksnelheid, experimenteren

  3. Rust → correctheid onder randvoorwaarden, zonder performance op te geven

  4. Go → pragmatische services

  5. C++ → ultieme controle, oude ecosystemen, scherpe randjes

Rust gaf me niet het gevoel minder ervaren te zijn. Het gaf me het gevoel dat mijn ervaring eindelijk een compiler had die me rugdekking gaf — ook als hij me irriteerde.

Tot slot

Ik ben deze kerst niet “overgestapt” op Rust.

Ik heb het erbij gepakt.

Ja, ik heb met traits geruzied.

Ja, ik heb numerieke bounds vervloekt.

Ja, ik ben een paar uur kwijtgeraakt aan de borrow checker.

Maar het beklijfde.

2026 wordt een stukje roestiger.

En daar kijk ik oprecht naar uit. 🦀

image (2).webp
no image placeholder

Softwareontwikkeling ontmoeilijken