Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
1

soot, solar, sedimentation, sin, & 'centers

from wingolog [alt+shift+b] in programming

Good evening, friends. Tonight I have a few loosely-knit stories. A couple years ago, my house was heated by a . It was awful from both an environmental and a geopolitical perspective: environmental, as I would emit somewhere around 2.5 tons of CO2 equivalent per year to heat my home, which compares poorly to the target total CO2e emissions of 2 tons per year per person; and geopolitical, because although France gets 40% of its gas from Norway, with whom we have no beef, all the rest is a problem in some way. (Algeria, 10%, is the least of my worries; the 20% for Russia and the US respectively are the most, followed by 10% for the Gulf states.)condensing gas boiler Still, natural gas is better than fuel oil, which we had at my former rental house. It is a lamentably visceral experience to call up the fuel provider and say, yes, , can you drive a diesel-powered tanker truck out to my house, unroll the hose, and pour out 1500 liters of toxic fuel oil into a tank under my garden. Yes, I will just burn it all. Sure, see you again next year.s’il vous plaît Some friends of mine recently had their fuel boiler die, which is itself an experience: one of them came over to visit, completely covered in soot, saying that the chimneysweep (whom he also has to call every year) said that his boiler is on its way out, that the chimney is completely clogged, and now because of the cleaning his basement is also covered in soot; awful. What to replace it with? Apparently despite the prohibition on new fuel-oil boiler installs, it might be possible to just install a new one; or they could hook up to natural gas from the street; or they could install a heat pump. Which to do? To all these questions there is a moral answer, which we can phrase in terms in CO2 emissions and localized PM2.5 pollution, and it is always and everywhere to stop burning things. But fortunately we don’t need to rely only on moralism: electrification is just better, in essentially all ways. Owning and...
16th May 2026

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from wingolog

the value of a performance oracle

Over on his excellent blog, from having ported a bytecode virtual machine to . He finds that his tail-calling interpreter written in Rust beats his switch-based interpreter, and even beats hand-coded assembly on some platforms.Matt Keeter posts some resultstail-calling style He also compares tail-calling versus switch-based interpreters on WebAssembly, and concludes that performance of tail-calling interpreters in Wasm is terrible: In this article, I would like to argue the opposite: patterns that generate good assembly map just fine to the Wasm stack machine, and the underperformance of V8, SpiderMonkey, and Wasmtime is an accident. I re-ran Matt’s experiment locally on my x86-64 machine (AMD Ryzen Threadripper PRO 5955WX). I tested three toolchains: For each of these toolchains, I tested Raven as implemented in Rust in both “switch-based” and “tail-calling” modes. Additionally, Matt has a Raven implementation written directly in assembly; I test this as well, for the native toolchain. All results use nightly/git toolchains from 7 April 2026. My results confirm Matt’s for the native and wasmtime toolchains, but wastrel puts them in context: We can read this chart from left to right: a switch-based interpreter written in Rust is 1.5× slower than a tail-calling interpreter, and the tail-calling interpreter just about reaches the speed of hand-written assembler. (Testing on AArch64, Matt even sees the tail-calling interpreter beating his hand-written assembler.) Then moving to WebAssembly run using Wasmtime, we see that Wasmtime takes 4.3× as much time to run the switch-based interpreter, compared to the fastest run from the hand-written assembler, and worse, actually shows 6.5× overhead for the tail-calling interpreter. Hence Matt’s conclusions: there must be something wrong with WebAssembly. But if we compare to , we see a different story: Wastrel runs the basic interpreter with 2.4× overhead, and the tail-calling interpreter improves on this marginally with a 2.3x overhead. Now, granted, two-point-whatever-x is not one; Matt’s Raven VM still runs slower in Wasm than when compiled natively. Still, a tail-calling interpreter is inherently a pretty good idea.Wastrel When I think about it, there’s no reason that the switch-based interpreter should be slower when compiled via Wastrel than when compiled via . Memory accesses via Wasm should actually be cheaper due to 32-bit pointers, and all the rest of it should be pretty much the same. I looked at the assembly that Wastrel produces and I see most of the patterns that I would expect.rustc I do see, however, that Wastrel repeatedly reloads a value, containing the address (and size) of main memory. I need to figure out a way to keep this value in registers. I don’t know what’s up with the other Wasm implementations here; for Wastrel, I get 98% of time spent in the single interpreter function, and surely this is bread-and-butter for an optimizing compiler such as Cranelift. I tried pre-compilation in Wasmtime but it didn’t help. It could be that there is a different Wasmtime configuration that allows for higher performance.struct memory Things are more nuanced for the tail-calling VM. When compiling natively, Matt is careful to use a calling convention for the opcode-implementing functions, which allows LLVM to allocate more registers to function parameters; this is just as well, as it seems that his opcodes have around 9 parameters. Wastrel currently uses GCC’s default calling convention, which only has 6 registers for non-floating-point arguments on x86-64, leaving three values to be passed via global variables (described ); this obviously will be slower than the native build. Perhaps Wastrel should add the equivalent annotation to tail-calling functions.preserve_nonehere On the one hand, Cranelift (and V8) are a bit more constrained than Wastrel by their function-at-a-time compilation model that privileges latency over throughput; and as they allow Wasm modules to be instantiated at run-time, functions are effectively closures, in which the “instance” is an additional hidden dynamic parameter. On the other hand, these compilers get to choose an ABI; last I looked into it, SpiderMonkey used the equivalent of , which would allow it to allocate more registers to function parameters. But it doesn’t: you only get 6 register arguments on x86-64, and only 8 on AArch64. Something to fix, perhaps, in the Wasm engines, but also something to keep in mind when making tail-calling virtual machines: there are only so many registers available for VM state.preserve_none Well friends, you know us compiler types: we walk a line between collegial and catty. In that regard, I won’t deny that I was delighted when I saw the Wastrel numbers coming in better than Wasmtime! Of course, most of the credit goes to GCC; Wastrel is a relatively small wrapper on top. But my message is not about the relative worth of different Wasm implementations. Rather, it is that : a fast implementation of a particular algorithm is of use to everyone who uses that algorithm, whether they use that implementation or not.performance oracles are a public good This happens in two ways. Firstly, faster implementations advance the state of the art, and through competition-driven convergence will in time result in better performance for all implementations. Someone in Google will see these benchmarks, turn them into an OKR, and golf their way to a faster web and also hopefully a bonus. Secondly, there is a dialectic between the state of the art and our collective imagination of what is possible, and advancing one will eventually ratchet the other forward. We can forgive the conclusion that “patterns which generate good assembly don’t map well to the WASM stack machine” as long as Wasm implementations fall short; but having showed that good performance is possible, our toolkit of applicable patterns in source languages also expands to new horizons. Well, that is all for today. Until next time, happy hacking! 1.2× slower on Firefox, 3.7× slower on Chrome, and 4.6× slower in wasmtime. I guess patterns which generate good assembly don't map well to the WASM stack machine, and the JITs aren't smart enough to lower it to optimal machine code. some numbers where does the time go the value of time Compiled natively via / cargorustc Compiled to WebAssembly, then run with Wasmtime Compiled to WebAssembly, then run with Wastrel

7th Apr 2026 • 1 votes
free trade and the left, ter: mises and my apostasy

Good evening. Let’s talk about free trade! Last time, , which looks at how the cause of free trade was taken up by a motley crew of anti-imperialists, internationalists, pacifists, marxists, and classical liberals in the nineteenth century. Protectionism was the prerogative of empire—only available to those with a navy—and it so it makes sense that idealists might support “peace through trade”. So how did free trade go from a cause of the “another world is possible” crowd to the halls of the WTO? Did we leftists catch a case of buyer’s remorse, or did the goods delivered simply not correspond to the order?we discussed Marc-William Palen’s Pax Economica To make an attempt at an answer, we need more history. From the acknowledgements of :Quinn Slobodian’s Globalists Slobodian’s approach is to pull on the thread that centers around the WTO itself. He ends up identifying what he calls the “Geneva School” of neoliberalism: from Mise’s circle in Vienna, to the International Chamber of Commerce in Paris, to the Hayek-inspired Mont Pèlerin Society, to Petersmann of the WTO precursor GATT organization, Röpke of the Geneva Graduate Institute of International Studies, and their lesser successors of the 1970s and 1980s. The thesis that Slobodian ends up drawing is that neoliberalism is not actually a fundamentalism, but rather an ideology that placed the value of free-flowing commerce above everything else: above democracy, above sovereignty, above peace, and that as such it actually requires active instutional design to protect commerce from the dangers of, say, hard-won gains by working people in one country (Austria, 1927), expropriation of foreign-owned plantations in favor of landless peasants (Guatemala, 1952), internal redistribution within countries transitioning out of minority rule (South Africa, 1996), decolonization (1945-1975 or so), or just the election of a moderate socialist at the ballot box (Chile, 1971).laissez-faire Now, dear reader, I admit to the conceit that if you are reading this, probably you are a leftist also, and if not, at least you are interested in understanding how it is that we think, with what baubles do we populate our mental attics, that sort of thing. Well, friend, you know that by the time we get to Chile and Allende we are stomping and clapping our hands and shouting in an extasy of indignant sectarian righteousness. And that therefore should we invoke the spectre of neoliberalism, it is with the deepest of disgust and disdain: this project and all it stands for is against me and mine. I hate it like I hated Henry Kissinger, which is to say, .a lot, viscerally, it hurts now to think of it, rest in piss you bastard And yet, I’m still left wondering what became of the odd alliance of Marx with Manchester liberalism. Palen’s continues to sketch a thin line through the twentieth century, focusing on showing the continued presence of commercial-peace exponents despite it not turning out to be our century. But the rightward turn of the main contingent of free-trade supporters is not explained. I have an idea about how it is that this happened; it is anything but scholarly, but here we go.Pax Economica Let us take out our coarsest brush to paint a crude story: the 19th century begins in the wake of the American and French revolutions, making the third estate and the bourgeoisie together the revolutionary actors of history. It was a time in which “we” could imagine organizing society in different ways, the age of the utopian imaginary, but overlaid with the structures of the old, old money, old land ownership, revanchist monarchs, old power, old empire. In this context, Cobden’s was insurgent, heterodox, asking for a specific political change with the goal of making life on earth better for the masses. Free trade was a means to an end. Not all Cobdenites had the same ends, but Marx and Manchester both did have ends, and they happened to coincide in the means.Anti-Corn Law League Come the close of the Great War in 1918, times have changed. The bourgeoisie have replaced the nobility as the incumbent power, and those erstwhile bourgeois campaigners now have to choose between idealism and their own interest. But how to choose? Some bourgeois campaigners will choose a kind of humanist notion of progress; this is the thread traced by Palen, through the , the Young Women’s Christian Association, the , and others.Carnegie Endowment for International PeaceHaslemere Group Some actors are not part of the hegemonic bourgeoisie at all, and so have other interests. The newly independent nations after decolonization have more motive to upend the system than to preserve it; their approach to free trade has both tactical and ideological components. Tactical, in the sense that they wanted access to first-world markets, but also sometimes some protections for their own industries; ideological, in the sense that they often acted in solidarity with other new nations against the dominant powers. In addition to the new nations, the Soviet bloc had its own semi-imperial project, and its own specific set of external threats; we cannot blame them for being tactical either. And then you have Ludwig von Mises. Slobodian hints at Mises’ youth in the Austro-Hungarian empire, a vast domain of many languages and peoples but united by trade and the order imposed by monarchy. After the war and the breakup of the empire, I can only imagine—and here I am imagining, this is not a well-evidenced conclusion—I imagine he felt a sense of loss. In the inter-war, he holds court as the of the Vienna Chamber of Commerce, trying to put the puzzle pieces back together, to reconstruct the total integration of imperial commerce, but from within . When in 1927, , the city went on general strike, and workers burned down the ministry of justice. Police responded violently, killing 89 people and injuring over 1000. Mises was delighted: order was restored.doyenRed Viennaa court decision acquitted a fascist milicia that fired into a crowd, killing a worker and a child And now, a parenthesis. I grew up Catholic, in a ordinary kind of way. Then in my early teens, I concluded that if faith meant anything, it has to burn with a kind of fervor; I became an evangelical Catholic, if such is a thing. There were special camps you could go to with intense emotional experiences and people singing together and all of that is God, did you know? Did you know? The feelings attenuated over time but I am a finisher, and so I got confirmed towards the end of high school. I went off to university for physics and stuff and eventually, painfully, agonizingly concluded there was no space for God in the equations. Losing God was incredibly traumatic for me. Not that I missed, like, the idea of some guy, but as someone who wants things to make sense, to have meaning, to be based on something, anything at all: losing a core value or morality invalidated so many ideas I had about the world and about myself. What is the good life, a life well led? What is true and right in a way that is not contingent on history? I am embarrassed to say that for a while I took the UN declaration of human rights to be axiomatic. When I think about Mise’s reaction to the 1927 general strike in Vienna, I think about how I scrambled to find something, anything, to replace my faith in God. As the space for God shrank with every advance in science, some chose to identify God with his works, and then to progressively ascribe divine qualities to those works: perhaps commerce is axiomatically Good, and yet ineffable, in the sense that it is Good on its own, and that no mortal act can improve upon it. How else can we interpret Hayek’s relationship with the market except as awe in the presence of the divine? This is how I have come to understand the neoliberal value system: a monotheism with mammon as godhead. There may be different schools within it, but all of the faithful worship the same when they have to choose between, say, commerce and democracy, commerce and worker’s rights, commerce and environmental regulation, commerce and taxation, commerce and opposition to apartheid. It’s a weird choice of deity. Now that God is dead, one could have chosen anything to take His place, and these guys chose the “global economy”. I would pity them if I still had a proper Christian heart. I think that neoliberals made a miscalculation when they concluded that the peace of is not predicated on justice. Sure, in the short run, you can do business with Pinochet’s Chile, privatize the national mining companies, and cut unemployment benefits, but not without incurring moral damage; people will see through it, in time, as they did in Seattle in 1999. Slobodian refers to the ratification of the WTO as a Pyrrhic victory; in their triumph, neoliberals painted a target on their backs.doux commerce Where does this leave us now? And what about Mercosur? I’m starting to feel the shape of an answer, but I’m not there yet. I think we’ll cover the gap between Seattle and the present day in a future dispatch. Until then, let’s take care of one other; as spoke the prophet Pratchett, there’s no justice, just us. This book is a long-simmering product of the Seattle protests against the World Trade Organization in 1999. I was part of a generation that came of age after the Cold War's end. We became adolescents in the midst of talk of globalization and the End of History. In the more hyperactive versions of this talk, we were made to think that nations were over and the one indisputable bond uniting humanity was the global economy. Seattle was a moment when we started to make collective sense of what was going on and take back the story line. I did not make the trip north from Portland but many of my friends and acquaintances did, painting giant fists red to strap to backpacks and coming back with takes of zip ties and pepper spray, nights in jail, and encounters with police—tales they spun into war stories and theses. This book is an apology for not being there and an attempt to rediscover in words what the concept was that they went there to fight. papier-mâché two theologies means without end

6th Mar 2026 • 1 votes
ahead-of-time wasm gc in wastrel

Hello friends! Today, a quick note: the ahead-of-time WebAssembly compiler now supports managed memory via garbage collection!Wastrel The quickest demo I have is that you should check out and build wastrel itself: Then run a quick check with :hello, world Now give a check to , a classic GC micro-benchmark:gcbench We set to get those last 4 lines. So, this is a microbenchmark: it runs for only 138 ms, and the heap is tiny (26.7 MB). It does collect 30 times, which is something.WASTREL_PRINT_STATS=1 I know what you are thinking: OK, it’s a microbenchmark, but can it tell us anything about how Wastrel compares to V8? Well, probably so: Which is to say, V8 takes more CPU time (230ms vs 209ms) and more wall-clock time (200ms vs 138ms). Also it uses twice as much managed memory (48 MB vs 26.7 MB), and more than that for the total process (88 MB vs 34 MB, not shown). Let’s try with , which at least has a larger active heap size. This time we’ll compile a binary and then run it:quads Compare to V8 via node: Which is to say, : 2460ms (v8) vs 849ms (wastrel), and 383MB vs 141 MB.wastrel is almost three times as fast, while using almost three times less memory So, yes, the V8 times include the time to compile the wasm module on the fly. No idea what is going on with tiering, either, but I understand that tiering up is a thing these days; this is node v22.14, released about a year ago, for what that’s worth. Also, there is a V8-specific module to do some impedance-matching with regards to strings; in Wastrel they are WTF-8 byte arrays, whereas in Node they are JS strings. But it’s not a string benchmark, so I doubt that’s a significant factor. I think the performance edge comes in having the program ahead-of-time: you can statically allocate type checks, statically allocate object shapes, and the compiler can see through it all. But I don’t really know yet, as I just got everything working this week. Wastrel with GC is demo-quality, thus far. If you’re interested in the back-story and the making-of, see article from October, or the FOSDEM talk from last week:my intro to Wastrel Slides , if that’s your thing.here More to share on this next week, but for now I just wanted to get the word out. Happy hacking and have a nice weekend! hello, world is it good? improving on v8, really? zowee! git clone https://codeberg.org/andywingo/wastrel cd wastrel guix shell # alternately: sudo apt install guile-3.0 guile-3.0-dev \ # pkg-config gcc automake autoconf make autoreconf -vif && ./configure make -j $ ./pre-inst-env wastrel examples/simple-string.wat Hello, world! $ WASTREL_PRINT_STATS=1 ./pre-inst-env wastrel examples/gcbench.wat Garbage Collector Test Creating long-lived binary tree of depth 16 Creating a long-lived array of 500000 doubles Creating 33824 trees of depth 4 Top-down construction: 10.189 msec Bottom-up construction: 8.629 msec Creating 8256 trees of depth 6 Top-down construction: 8.075 msec Bottom-up construction: 8.754 msec Creating 2052 trees of depth 8 Top-down construction: 7.980 msec Bottom-up construction: 8.030 msec Creating 512 trees of depth 10 Top-down construction: 7.719 msec Bottom-up construction: 9.631 msec Creating 128 trees of depth 12 Top-down construction: 11.084 msec Bottom-up construction: 9.315 msec Creating 32 trees of depth 14 Top-down construction: 9.023 msec Bottom-up construction: 20.670 msec Creating 8 trees of depth 16 Top-down construction: 9.212 msec Bottom-up construction: 9.002 msec Completed 32 major collections (0 minor). 138.673 ms total time (12.603 stopped); 209.372 ms CPU time (83.327 stopped). 0.368 ms median pause time, 0.512 p95, 0.800 max. Heap size is 26.739 MB (max 26.739 MB); peak live data 5.548 MB. $ guix shell node time -- \ time node js-runtime/run.js -- \ js-runtime/wtf8.wasm examples/gcbench.wasm Garbage Collector Test [... some output elided ...] total_heap_size: 48082944 [...] 0.23user 0.03system 0:00.20elapsed 128%CPU (0avgtext+0avgdata 87844maxresident)k 0inputs+0outputs (0major+13325minor)pagefaults 0swaps $ ./pre-inst-env wastrel compile -o quads examples/quads.wat $ WASTREL_PRINT_STATS=1 guix shell time -- time ./quads Making quad tree of depth 10 (1398101 nodes). construction: 23.274 msec Allocating garbage tree of depth 9 (349525 nodes), 60 times, validating live tree each time. allocation loop: 826.310 msec quads test: 860.018 msec Completed 26 major collections (0 minor). 848.825 ms total time (85.533 stopped); 1349.199 ms CPU time (585.936 stopped). 3.456 ms median pause time, 3.840 p95, 5.888 max. Heap size is 133.333 MB (max 133.333 MB); peak live data 82.416 MB. 1.35user 0.01system 0:00.86elapsed 157%CPU (0avgtext+0avgdata 141496maxresident)k 0inputs+0outputs (0major+231minor)pagefaults 0swaps $ guix shell node time -- time node js-runtime/run.js -- js-runtime/wtf8.wasm examples/quads.wasm Making quad tree of depth 10 (1398101 nodes). construction: 64.524 msec Allocating garbage tree of depth 9 (349525 nodes), 60 times, validating live tree each time. allocation loop: 2288.092 msec quads test: 2394.361 msec total_heap_size: 156798976 [...] 3.74user 0.24system 0:02.46elapsed 161%CPU (0avgtext+0avgdata 382992maxresident)k 0inputs+0outputs (0major+87866minor)pagefaults 0swaps

6th Feb 2026 • 1 votes
pre-tenuring in v8

Hey hey happy new year, friends! Today I was going over some V8 code that touched : allocating objects directly in the old space instead of the nursery. I knew the theory here but I had never looked into the mechanism. Today’s post is a quick overview of how it’s done.pre-tenuring In a JavaScript program, there are a number of source code locations that allocate. Statistically speaking, any given allocation is likely to be short-lived, so generational garbage collection partitions freshly-allocated objects into their own space. In that way, when the system runs out of memory, it can preferentially reclaim memory from the nursery space instead of groveling over the whole heap. But you know what they say: there are lies, damn lies, and statistics. Some programs are outliers, allocating objects in such a way that they don’t die young, or at least not young enough. In those cases, allocating into the nursery is just overhead, because minor collection won’t reclaim much memory (because too many objects survive), and because of useless copying as the object is scavenged within the nursery or promoted into the old generation. It would have been better to eagerly tenure such allocations into the old generation in the first place. (The more I think about it, the funnier is as a term; what if some PhD programs could pre-allocate their graduates into named chairs? Is going straight to industry the equivalent of dying young? Does collaborating on a paper with a full professor imply a write barrier? But I digress.)pre-tenuring Among the set of allocation sites in a program, a subset should pre-tenure their objects. How can we know which ones? There is a literature of static techniques, but this is JavaScript, so the answer in general is dynamic: we should observe how many objects survive collection, organized by allocation site, then optimize to assume that the future will be like the past, falling back to a general path if the assumptions fail to hold. The high-level overview of how V8 implements pre-tenuring is based on per-program-point objects, and per-allocation objects that point back to their corresponding AllocationSite. Initially, V8 doesn’t know what program points would profit from pre-tenuring, and instead allocates everything in the nursery. Here’s a quick picture:AllocationSiteAllocationMemento Here we show that there are two allocation sites, and . V8 is currently allocating into a linear allocation buffer (LAB) in the nursery, and has allocated three objects. After each of these objects is an ; in this example, and are objects that point to and points to . When V8 allocates an object, it (if available; it’s possible an allocation comes from C++ or something where we don’t have an ).Site1Site2AllocationMementoM1M3AllocationMementoSite1M2Site2AllocationSiteincrements the “created” counter on the corresponding AllocationSite When the free space in the LAB is too small for an allocation, V8 gets another LAB, or collects if there are no more LABs in the nursery. When V8 does a minor collection, as the scavenger visits objects, it will . If so, it dereferences the memento to find the , then increments its “found” counter, and adds the to a set. , it is enqueued for a pre-tenuring decision; get marked for pre-tenuring.look to see if the object is followed by an AllocationMementoOnce an AllocationSite has had 100 allocationssites with 85% survivalAllocationSiteAllocationSite If an allocation site is marked as needing pre-tenuring, the code in which it is embedded it will get de-optimized, and then next time it is optimized, the code generator arranges to allocate into the old generation instead of the default nursery. Finally, if a major collection collects more than 90% of the old generation, V8 , under the assumption that pre-tenuring was actually premature.resets all pre-tenured allocation sites What kinds of allocation sites are eligible for pre-tenuring? Sometimes it depends on object kind; wasm memories, for example, are almost always long-lived, so they are always pre-tenured. Sometimes it depends on who is doing the allocation; allocations from the bootstrapper, literals allocated by the parser, and many allocations from C++ go straight to the old generation. And sometimes the compiler has enough information to determine that pre-tenuring might be a good idea, as when it .generates a store of a fresh object to a field in an known-old object But otherwise I thought that the whole AllocationSite mechanism would apply generally, to any object creation. It turns out, nope: it seems to only apply to object literals, array literals, and . Weird, right? I guess it makes sense in that these are the ways to create objects that also creates the field values at creation-time, allowing the whole block to be allocated to the same space. If instead you make a pre-tenured object and then initialize it via a sequence of stores, this would likely create old-to-new edges, preventing the new objects from dying young while incurring the penalty of copying and write barriers. Still, I think there is probably some juice to squeeze here for pre-tenuring of class-style allocations, at least in the optimizing compiler or in short inline caches.new Array I suspect this state of affairs is somewhat historical, as the AllocationSite mechanism seems to have originated with and V8’s “boilerplate” object literal allocators; both of these predate per-AllocationSite pre-tenuring decisions.typed array storage strategies Well that’s adaptive pre-tenuring in V8! I thought the “just stick a memento after the object” approach is pleasantly simple, and if you are only bumping creation counters from baseline compilation tiers, it likely amortizes out to a win. But does the restricted application to literals point to a fundamental constraint, or is it just accident? If you have any insight, let me know :) Until then, happy hacking! allocation sites my runtime doth object tenure for me but not for thee fin A linear allocation buffer containing objects allocated with allocation mementos

5th Jan 2026 • 1 votes

More in programming

Contract testing implementation challenges

This post was previously published through my newsletter on October 19, 2026. From time to time, I will republish newsletter issues on my blog here if I think people (and search engines) might benefit from it. If you want to read everything I’ve written once it is posted, I recommend signing up for the newsletter. For the last 5-6 years or so, I’ve been talking about, teaching and helping teams implement contract testing on a regular basis. To make that more concrete: at the moment, I’m having ongoing conversations with four different potential clients about helping them in some way with their contract testing implementation, and so far, I’ve run my contract testing workshop four times this year. It probably doesn’t come as a surprise to you when I say that I really like the concept of contract testing as a means of addressing integration testing challenges in distributed software systems. However, no matter if I’m speaking, teaching or implementing contract testing, certain challenges almost always come up at some point, and I want to highlight some of those today. Understanding the concept of contract testing First of all, it often takes people a while to understand the concept of contract testing, especially when they’re used to what I call the ‘traditional’ approach to integration testing: deploying the systems and services in scope to a shared testing environment and then testing them ‘as a whole’. Of course, the more distributed your system and your development process is, and the higher the deployment frequency, the more complex and the slower this integration testing approach is going to be. The premise behind contract testing is to break that integration testing puzzle down into small chunks of individual consumer-provider pairs, and then test the integration between those two in an asynchronous manner. By asynchronous, I mean that there is no need to deploy consumer and provider into a shared environment; both parties perform their part of the process in their own, local development environment. This means you can detect potential integration issues before you deploy, instead of stumbling onto them after you do so. This makes contract testing (or contract-based integration testing, to use its proper name) a significantly different approach to integration testing compared to the more ‘traditional’ approach. In my experience, it usually takes people time to wrap their head around how the process actually works, which steps you should take and in which order, and what you (do not yet) know after each step. It often takes going through several contract testing cycles before people start to ‘get it’. That’s not their fault, that is to be expected, since the contract-based approach to integration testing is, again, quite different from what they’ve been doing for so long. To better cater to this, I redesigned my contract testing workshop a year and a half or so ago. It is now a full-day workshop (half a day is simply too short), and I take much smaller steps and repeat them more often. From what I see, this has led to a better understanding of the concepts with my audience, and that’s the whole point. Contract testing === Pact I’ve talked to quite a few teams that had heard of contract testing somewhere, decided that that was the way out of their integration testing problems, and then immediately started writing contract tests with Pact. Understandable, because Pact is a very useful, very powerful and very popular tool, plus, it’s open source, which makes it easy for teams to get started. Often, they skipped a step in the process. Pact is very much a consumer-driven contract testing tool by nature, and while consumer-driven contract testing is the richest and most powerful of the different approaches to contract testing, it is not necessarily the best fit for every team and every context. It’s a classic example of using the wrong tool for the problem at hand, because they didn’t take enough time looking at the problem and the available solutions. That’s not the problem of Pact, even though it is often framed that way (‘Pact didn’t solve my problems, therefore Pact is not a good tool’). That’s a ‘we didn’t fully understand the problem and the context’ problem. Contract testing removes the need for communication Another challenge that I often see when I talk about or help teams with contract testing is the fact that teams don’t talk to each other. This then leads to integration issues, because team A expects something from team B that team B doesn’t supply. Contract testing is not the solution to these problems. It can’t be - tools alone do not solve problems, let alone communication problems. What contract testing does do is make potential integration issues visible early on in the development process, often earlier than (again) more ‘traditional’ approaches to integration testing. That’s where the value of contract testing can be found. It is not a means to replace communication between teams. In fact, and this is especially true for consumer-driven contract testing, contract testing cannot succeed without good communication between consumer and provider teams. Contract testing replaces all other types of integration testing This one comes up less often than it used to, but sometimes, I still hear people saying that when they will have contract-based integration tests in place, they don’t need other types of integration tests anymore - including E2E tests. That’s simply not true. While contract testing is a great way to find out earlier about the impact of a change in a specific consumer or provider further downstream, in many cases, I wouldn’t rely on these tests alone before moving to production. Because of its asynchronous nature, contract-based integration testing only verifies whether a consumer and a provider speak the same language - can a consumer understand the message returned by a provider in a specific situation? It does not verify that the request or the response message reaches the other party in the first place, for example. In other words, it doesn’t test connectivity between a consumer and a provider. And because integration testing is broken down into individual consumer-provider pairs, you don’t see the entire system working ‘as a whole’. This means you might want to keep a few end-to-end tests in place, even when you’ve got good contract testing coverage across the board. The above is not a complete list of challenges with contract testing, but the ones I mentioned here are those that come up most often.

19 hours ago • 1 votes
Suffering as a Feature

Have you seen this? If you haven't, you should. I think everyone needs to. Wealth inequality on a scale this extreme is almost impossible to explain. You have to experience it to understand. Go ahead. Try it out. Where is the top of this graph? Good question. Keep

yesterday • 1 votes
The upvote dilemma

Hiding upvotes on the discovery feed

2 days ago • 2 votes
The slopocalypse survival guide

Slop is without a doubt everywhere. Be it in restaurant’s menus, music playlists, or online game storefronts, it is now impossible to escape it. Yet, I’ve never met anyone who was actually looking forward to consuming that. No matter how hard it’s shoved down our throats, the human longing to connect with other people through art still remains. Raymond Kotewicz They will not let you filter A simple solution would be to have slop filters. Automatically label AI-generated trash, and let users hide it if they don’t want to see it. So far, I don’t think any of the major internet platforms has implemented this. The common excuse for why they don’t let you easily filter out slop is that it would be technically too difficult. Let me be clear with everyone here: this is complete bullshit. We’re talking about companies that can hire some of the most talented engineers in the world. I don’t think anyone seriously believes they can’t come up with a way to guess if a file has been generated by AI or not. 90% of the slop out there stands out so much everyone can see how it was made after looking at it for 5 seconds. A more plausible reason for the lack of slop filter is that they are simply testing out the waters. They are checking if users will tolerate it. The question tech executives want answered is: will people buy this garbage? And if the answer to that question is yes, here’s what they will do: they will start generating it themselves. They don’t need the useless meat proxies who think typing ten words and pressing enter makes them creative. They definitely don’t want to verse anyone royalties when they could just be making a one time purchase of tokens. If you think this is not real, just ask Tim Sweeney. I bet he will be more than happy to confirm. Roman Navarro Curation by humans for humans So now that it’s clear that tech companies will not save us from drowning in slop, it’s time to turn back to actual humans instead. The good news is they are a lot of people who are here to help you. There are thousands of people on the internet who will search through mountains of content to find the perfect piece of art they want to share with the world. We don’t explicitly call them curators. They are streamers, bloggers, journalists, DJs, overly enthusiast fans, or simply your friends. Some of those people are seriously amazing. There are DJs out there who will spend thousands of hours digging through crates to craft you the perfect ninety minutes of music. Why do you still need those machine-generated playlists? The alternative to blindly trusting the output of a recommendation algorithm isn’t always to become an expert in every field of art. Sometimes you just have to put the trust you had in a machine back into another person. Back to the real world? The real long term solution would be to stop relying only on the internet for distribution. This is already a thing in the music industry. Every city has a record shop that will sell you a carefully selected set of vinyls. For many musicians, physical sales (and concerts) are a much better source of income than streaming. The same goes for the movie. While text-to-video AI is a thing, the real money isn’t made by generating 30 second TikTok dramas. The real money comes from people paying tickets to see a full-length movie in a theater. Sadly I’m not too optimistic about my own field: video games. Somehow it seems the direction we’ve taken is the opposite. We’re all in on online distributions platforms. We have fully accepted them as our new digital overlords. Next month GTA V is coming out without a disk in the box. Sony already announced that the next Playstation will not support physical media. Physical distribution is not even mentioned in the pitch of the average indie publisher. In Breda, the small Dutch city where I live, we used to have two dedicated video games shop. Higher interests rates, expensive rents, and various policy failures have done their jobs: they are both closed. I don’t think this is a good sign for the survivability of the gaming industry.

2 days ago • 2 votes
LARPing with Agents (and Why It Works)

Understanding how assigning anthropomorphic traits to agents can improve their effectiveness and interaction.

2 days ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in