Bun is in zes dagen door AI herschreven in Rust. De les gaat niet over Rust.

Bun's core werd van Zig naar Rust geport — meer dan een miljoen regels, grotendeels door Claude-agents, met 99,8% testcompatibiliteit. De kop is de AI. De echte les, ook voor .NET'ers, is dat de testsuite de specificatie was. Dit is wat je er werkelijk uit moet halen.

Jean-Pierre Broeders

Freelance .NET Developer

29 juni 202611 min. leestijd
Bun is in zes dagen door AI herschreven in Rust. De les gaat niet over Rust.

Bun is in zes dagen door AI herschreven in Rust. De les gaat niet over Rust.

Eén tweet van Jarred Sumner klom deze week naar de voorpagina van Hacker News, met een getal waar iedereen even van stopte met scrollen: Bun's experimentele Rust-herschrijving haalt 99,8% testcompatibiliteit op Linux x64 glibc. Bun — de JavaScript-runtime en toolchain die al jaren in Zig geschreven is — heeft nu een parallelle implementatie in Rust. Volgens berichtgeving van The Register voegde de merge meer dan een miljoen regels code toe over duizenden commits, kromp het binary met enkele megabytes, werden onderweg een paar memory leaks gefixt, en was de code grotendeels gegenereerd door Claude-AI-agents die ongeveer zes dagen draaiden op een cluster van machines met veel geheugen.

Laat dat even bezinken. Een miljoen regels systeemcode, vertaald van het ene geheugenmodel naar het andere, uitkomend op 99,8% testpariteit, in minder dan een week, grotendeels door machines.

Het internet deed wat het internet doet en maakte er een ruzie van over Rust versus Zig, over of AI het "echt" geschreven heeft, over of 99,8% indrukwekkend is of juist angstaanjagend. Die discussie sla ik over, want als .NET-freelancer die in zijn dagelijks werk geen enkele regel Zig of Rust schrijft, vind ik dat de belangrijkste les helemaal niets met de betrokken talen te maken heeft. Het gaat erom waarom dit überhaupt mogelijk was — en die reden is rechtstreeks van toepassing op de C#-code die jij en ik schrijven.

Wat er feitelijk gebeurde

Ik houd me bij wat goed onderbouwd is. Bun's runtime was van oudsher in Zig geschreven. Sumner zei dat versie 1.3.14 "de laatste versie in Zig" zou zijn, en een zeer grote branch werd gemerged die de core herimplementeert in Rust. De genoemde motivatie is, volgens de berichtgeving, geheugenveiligheid: na jaren jagen op use-after-free-, double-free- en leakbugs in een taal zonder borrow checker, wilde het team garanties die door de compiler worden afgedwongen. Rust heeft bovendien een veel groter ecosysteem en een grotere groep bijdragers dan Zig, wat telt voor een project dat hulp van buitenaf wil.

Het opvallende zit in de methode. In plaats van een team mensen dat een jaar lang door een miljoen regels ploetert, deed AI het mechanische vertaalwerk grotendeels zelf, continu gevalideerd tegen Bun's bestaande testsuite. De Rust-build is voorlopig alleen canary, terwijl optimalisatie en opschoonwerk nog landen. Het cijfer van 99,8% geldt specifiek voor Linux x64 glibc; andere platforms lopen achter.

Ik beweer bewust niet dat de AI dit zonder toezicht deed of dat het productieklaar is. Canary is canary. Maar de technische vorm van dit verhaal is echt, en de moeite van het bestuderen waard.

De kop is de AI. De les is de testsuite.

Dit is het stuk dat je manier van werken zou moeten veranderen. Een grootschalige geautomatiseerde herschrijving is alleen verifieerbaar voor zover je een uitvoerbare definitie van "correct" hebt. Bun kon dit proberen — en het meten tot op 0,2% nauwkeurig — omdat er een uitgebreide testsuite is die tegelijk dienstdoet als specificatie. De agents werden niet vertrouwd; ze werden gecontroleerd, mechanisch, duizenden keren. De testsuite was het contract. De AI was niet meer dan een razendsnelle uitvoerder.

Draai het om. Als jouw codebase de vraag "is de nieuwe implementatie qua gedrag identiek aan de oude?" niet met één druk op de knop kan beantwoorden, dan maakt geen enkele hoeveelheid AI-capaciteit een herschrijving — of zelfs maar een stevige refactor — veilig. De bottleneck was nooit typesnelheid. Het was altijd verificatie.

Dit is de bril waardoor ik tegenwoordig elk "zullen we een agent dit laten refactoren?"-gesprek bekijk. De eerlijke eerste vraag is: waaruit zou blijken dat het nog werkt? Als het antwoord "we klikken wat rond en hopen het beste" is, dan heb je geen AI-probleem maar een testprobleem, en dat had je al lang voordat AI in beeld kwam.

Differential testing: de techniek die herschrijvingen meetbaar maakt

Het concrete gereedschap waar Bun op leunde is differential testing (of "characterization testing"): draai de oude en nieuwe implementatie tegen dezelfde invoer en bewijs dat ze identieke uitvoer produceren. Je hoeft niet te begrijpen waarom de code correct is; je hebt alleen nodig dat beide versies het eens zijn over een enorme hoeveelheid gevallen.

Dit is triviaal op te zetten in .NET, en het is veruit het waardevolste wat je kunt doen voordat je iets — mens of model — een kritiek component laat herschrijven. Stel je hebt een oude prijscalculatie en een nieuwe:

public interface IPricingEngine
{
    decimal Calculate(Order order);
}

public sealed record Order(
    IReadOnlyList<OrderLine> Lines,
    string CustomerTier,
    string? CouponCode);

public sealed record OrderLine(string Sku, int Quantity, decimal UnitPrice);

De differential test bewijst geen specifieke prijzen. Hij bewijst dat LegacyPricingEngine en RewrittenPricingEngine het nooit oneens zijn:

public class PricingParityTests
{
    private readonly IPricingEngine _old = new LegacyPricingEngine();
    private readonly IPricingEngine _new = new RewrittenPricingEngine();

    [Theory]
    [MemberData(nameof(GeneratedOrders))]
    public void Implementaties_Zijn_Het_Eens(Order order)
    {
        var verwacht = _old.Calculate(order);
        var werkelijk = _new.Calculate(order);

        Assert.Equal(verwacht, werkelijk);
    }

    public static IEnumerable<object[]> GeneratedOrders()
    {
        var rng = new Random(20260629); // vaste seed = reproduceerbaar
        var skus = new[] { "A1", "B2", "C3", "D4" };
        var tiers = new[] { "standard", "gold", "platinum" };
        var coupons = new string?[] { null, "SAVE10", "FREESHIP", "INVALID" };

        for (int i = 0; i < 5_000; i++)
        {
            var lines = Enumerable.Range(0, rng.Next(1, 6))
                .Select(_ => new OrderLine(
                    skus[rng.Next(skus.Length)],
                    rng.Next(1, 20),
                    Math.Round((decimal)(rng.NextDouble() * 100), 2)))
                .ToList();

            yield return new object[]
            {
                new Order(lines, tiers[rng.Next(tiers.Length)], coupons[rng.Next(coupons.Length)])
            };
        }
    }
}

Vijfduizend pseudo-willekeurige orders, een vaste seed voor reproduceerbaarheid, en één gelijkheidsassertie. Als dit groen is, heb je bewijs dat de herschrijving het gedrag behoudt. Op het moment dat het rood wordt, is de falende Order je bugrapport — volledig reproduceerbaar, zonder verhaal eromheen. Dit is precies de feedbackloop waar Bun's agents tegenaan draaiden, alleen op enorm veel grotere schaal.

Voor property-based generatie in plaats van handgeschreven loops zal FsCheck (ook vanuit C# bruikbaar) falende gevallen automatisch terugbrengen tot de minimale reproductie — goud waard als de diff tussen twee implementaties groot is.

Geheugenveiligheid is een feature die je kunt kopen zonder herschrijving

De andere helft van het Bun-verhaal is geheugenveiligheid, en hier herinner ik mijn mede-.NET'ers er vriendelijk aan dat wij al aan de comfortabele kant van deze afweging leven. De reden dat Bun een migratie van een miljard regels doorstaat, is dat Zig — net als C — je niet tegenhoudt om vrijgegeven geheugen te gebruiken. De CLR geeft ons al meer dan twintig jaar garbage collection, bounds checking en type safety. De klasse bugs die deze hele herschrijving motiveerde, bestaat in idiomatische C# vrijwel niet.

Waar het wel terug kan sluipen, is het unsafe- en interop-oppervlak — Span<T> over ruwe pointers, stackalloc, Marshal, unsafe-blokken. Als je daar voor performance toch naar grijpt, is dat precies waar een borrow-checker-achtige discipline loont, en waar ik een AI-reviewer als eerste op zou zetten. Een representatief voorbeeld van de afweging:

// Snel, maar nu draag jij het veiligheidsargument dat de compiler eerst voor je maakte.
public static unsafe int SumUnsafe(ReadOnlySpan<int> data)
{
    int total = 0;
    fixed (int* p = data)
    {
        for (int i = 0; i < data.Length; i++)
            total += p[i]; // geen bounds check — een verkeerde length hier is een geheugenbug
    }
    return total;
}

// De managed variant die de JIT al goed optimaliseert, en die geen geheugen kan corrumperen.
public static int SumSafe(ReadOnlySpan<int> data)
{
    int total = 0;
    foreach (var x in data)
        total += x;
    return total;
}

De les die Bun op de harde manier leerde — dat unmanaged geheugenbugs jaren kosten — heeft .NET door zijn ontwerp van tafel gehaald. Reserveer unsafe voor gemeten hot paths en houd het achter een pariteitstest zoals hierboven.

De trend achter de trend: het performance-tijdperk van de toolchain

Bun staat niet op zichzelf. Het is de nieuwste stap in een jarenlange migratie van developer-tooling naar systeemtalen: esbuild herschreef bundling in Go en liet al het andere traag lijken; Microsofts eigen port van de TypeScript-compiler naar native code joeg op een snelheidswinst van zo'n factor tien; Rust ligt inmiddels onder een hele generatie linters, formatters en package managers. De industrie besloot dat de tools die we honderden keren per dag draaien native performance verdienen.

.NET's antwoord op diezelfde druk is Native AOT. Als je CLI-tools of cold-start-gevoelige services levert, kun je vooraf compileren naar één native binary zonder runtime-JIT en met drastisch snellere opstarttijd:

<PropertyGroup>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>
  <StripSymbols>true</StripSymbols>
</PropertyGroup>
dotnet publish -c Release -r linux-x64

De afwegingen zijn reëel en mag je eerlijk benoemen: geen scenario's die zwaar op runtime-reflectie leunen zonder source generators, geen dynamisch assembly-laden, meer buildcomplexiteit, en je moet de gepubliceerde binary testen omdat trimming codepaden kan verwijderen die je unittests in de JIT-wereld nog wel raakten. Maar voor een tool die snel moet starten en als één bestand wordt geleverd, brengt AOT een .NET'er naar dezelfde bestemming die Bun najaagt — zonder het platform te verlaten.

Zou je AI je code moeten laten herschrijven?

Mijn eerlijke standpunt, aangescherpt door dit verhaal: de vraag is bijna altijd voorbarig. Vóór "kan AI dit herschrijven" beantwoord je "kan iets de herschrijving verifiëren." Bun's wonder van zes dagen draaide bovenop jaren aan opgebouwde tests. De AI comprimeerde het arbeidswerk; ze nam de noodzaak van een specificatie niet weg. Investeer je in differential- en property-based tests voor je kritieke componenten, dan krijg je twee dingen tegelijk — veiligere gewone refactors vandaag, en de optie om morgen een Bun-achtige geautomatiseerde migratie te doen als je die ooit nodig hebt.

En er is een stiller punt dat het overdenken waard is. Het indrukwekkendste in die thread is niet dat een model een miljoen regels Rust schreef. Het is dat een organisatie een testsuite had die goed genoeg was om het resultaat tot op 0,2% te vertrouwen. Die suite is het echte bezit. De AI is te huren; de verificatie niet. Bouw het ding dat je de waarheid over je code kan vertellen, en de rest — taal, tooling, zelfs wie of wat het schrijft — wordt een keuze in plaats van een sprong in het diepe.


Conclusie: Behandel Bun's herschrijving als een testverhaal, niet als een Rust-verhaal. Voeg differential tests toe vóór elke grote refactor, houd unsafe achter pariteitschecks, grijp naar Native AOT als opstarttijd en footprint ertoe doen, en onthoud dat de testsuite — niet de agent — een herschrijving van een miljoen regels meetbaar maakte.

Bronnen: Jarred Sumners aankondiging · Hacker News-discussie · The Register.

Wil je op de hoogte blijven?

Schrijf je in voor mijn nieuwsbrief of neem contact op voor freelance projecten.

Neem Contact Op