profile picture


Semver violations are common, better tooling is the answer

September 07, 2023 - 3270 words - 17 mins

This post is coauthored by Tomasz Nowak and Predrag Gruevski. It describes work the two of us did together with Bartosz Smolarczyk, Michał Staniewski, and Mieszko Grodzicki.

Anecdotally, cargo-semver-checks is a helpful tool for preventing the semver violations that every so often cause ecosystem-wide pain. This is why it earned a spot in the CI pipelines of key Rust crates like tokio, and also why the cargo team hopes to integrate it into cargo itself.

While anedotal evidence is nice, we wanted to get concrete data across a large sample of real-world Rust code. read more

Breaking semver in Rust by adding a private type, or by adding an import

May 08, 2023 - 3724 words - 19 mins

A few days ago, I started polls on Mastodon and Twitter whether adding a new private type, or an import, can ever be a major breaking change. The consensus was that this should be impossible.

I agree with that. It should be impossible.

I've discovered a way to cause a previously-public type or function to disappear from a crate's public API by making innocuous-seeming changes like adding a private type or adding an import, etc. It is not a hypothetical problem, either — I've found at least one real-world Rust project that has been affected by it.

read more

A definitive guide to sealed traits in Rust

April 05, 2023 - 2166 words - 11 mins

For the longest time, I thought that "sealed trait" in Rust was a singular concept implementable in one specific way. To prevent downstream crates from implementing your traits, you make the traits sealed — done, end of story. I was wrong! It turns out there are multiple ways to seal traits, forming a pleasant spectrum of options:

read more

Mediocrity can be a sign of excellence, and other stories

April 01, 2023 - 2208 words - 12 mins

Happy April 1st! This post is part of April Cools Club: an effort to publish genuine posts on topics our usual audience would find unexpected. The tech content will be back soon!

Over the many years I spent heavily involved in intern and full-time recruiting at $PREVIOUS_JOB, multiple people have commented something to the effect of: "How come Predrag always gets the best people?"

This post is a series of vignettes showing three of the less-obvious ideas that gave us an edge, read more

Re-exporting an enum with a type alias is breaking, but not major

March 06, 2023 - 813 words - 5 mins

We've already explored some of the dark corners of Rust semantic versioning on this blog:

read more

Speeding up Rust semver-checking by over 2000x

February 07, 2023 - 3926 words - 20 mins

This post describes work in progress: how cargo-semver-checks will benefit from the upcoming query optimization API in the Trustfall query engine. Read on to learn how a modern linter works under the hood, and how ideas from the world of databases can improve its performance.

read more

Moving and re-exporting a Rust type can be a major breaking change

January 31, 2023 - 1194 words - 6 mins
I recently embarked on a quest: revamp the cargo-semver-checks import-handling system so that moving and re-exporting an item stops being incorrectly flagged as a major breaking change. This is how crate authors can reorganize or rename items: just re-export the items in the original location under … read more

Some Rust breaking changes don't require a major version

January 26, 2023 - 1848 words - 10 mins
I've been saying for a while now that semantic versioning in Rust is tricky and full of unexpected edge cases. My last post mentioned that some Rust structs can be converted into enums without requiring a major version bump. It introduced a non-exhaustive struct called Chameleon that had no public f… read more

Turning a Rust struct into an enum is not always a major breaking change

January 24, 2023 - 1611 words - 9 mins
EDIT: The Rust API evolution RFC distinguishes between breaking changes and changes that require a new semver-major version (called major changes). All major changes are breaking, but not all breaking changes are major. Changing a struct to an enum is always breaking (as pointed out on r/rust) but i… read more

cargo-semver-checks today and in 2023

December 23, 2022 - 1946 words - 10 mins
cargo-semver-checks ends 2022 with 40,000 downloads from, able to prevent 30 different kinds of semver issues, and having done so in real-world use cases. Inspired by Yoshua Wuyts' "Rust in 2023 (by Yosh)" post, here are my thoughts on cargo-semver-checks in 2022, and what I look… read more

Falsehoods programmers believe about undefined behavior

November 27, 2022 - 2421 words - 13 mins
Undefined behavior (UB) is a tricky concept in programming languages and compilers. Over the many years I've been an industry mentor for MIT's 6.172 Performance Engineering course, An excellent class that I highly recommend. It's very thorough and hands-on, at the expense of also requiring a lot of… read more


October 03, 2022 - 1121 words - 6 mins

I had a lot of fun spending nights-and-weekends time participating in the HYTRADBOI Jam, a global hack week aimed at building "exciting and weird" data-centric solutions to familiar problems. The name HYTRADBOI might sound familiar: the jam is associated with the same conference where I gave my "How to Query (Almost) Everything" talk talk in April this year.

I jammed on two projects: one solo and one with a friend. The projects ultimately were very successful and mostly-successful, respectively. read more

Debugging Safari: If at first you succeed, don't try again

September 19, 2022 - 1887 words - 10 mins

The saying usually goes: "If at first you don't succeed, try, try again." But in the Safari web browser under the right conditions, trying again after succeeding once can get you in trouble. This is my recent debugging adventure. read more

Toward fearless cargo update

August 25, 2022 - 1866 words - 10 mins

I recently built cargo-semver-checks, a linter that ensures crates adhere to semantic versioning. This is why and how I built it.

Fearless development is a key theme throughout Rust. "If it compiles, it works", fearless concurrency, etc.

But there's one aspect of Rust (and nearly all other languages) that isn't entirely fearless yet: cargo update, upgrading the versions of the project's dependencies.

read more

Compiler Adventures, part 3: Value Numbering

May 17, 2022 - 3096 words - 16 mins
A beginner-friendly introduction to compilers: follow along as we build a compiler from scratch, or fork the code on GitHub and add your own optimizations too! In this episode: value numbering helps track how values are used in the program. Last time on Compiler Adventures, we implemented constant p… read more

To ace exams, get better at the easy questions

April 01, 2022 - 1732 words - 9 mins
Happy April 1st! A group of folks and I decided to do something different this year: instead of publishing fake things, we’re publishing real posts on very different topics than our readers usually expect from our blogs. The tech content will be back soon! Check out the other April Cools posts here.… read more

Compiler Adventures, part 2: Constant Propagation

February 17, 2022 - 2392 words - 12 mins
A beginner-friendly introduction to compilers: follow along as we build a compiler from scratch, or fork the code on GitHub and add your own optimizations too! In this episode: propagating constant values to eliminate more instructions. Last time on Compiler Adventures, we wrote an optimization that… read more

Compiler Adventures, part 1: No-op Instructions

February 03, 2022 - 1955 words - 10 mins
A beginner-friendly introduction to compilers: follow along as we build a compiler from scratch, or fork the code on GitHub and add your own optimizations too! In this episode: eliminating no-op instructions. What part of computer science feels most like arcane magic? I'd say compilers. "The ma… read more

How Paxos and Two-Phase Commit Differ

January 26, 2021 - 1115 words - 6 mins
Distributed systems courses frequently introduce the Paxos and two-phase commit (2PC) protocols in quick succession. On one hand, this is a reasonable educational choice, as Paxos and 2PC are both examples of consensus algorithms used in the real world. On the other, it leads many students toward th… read more