Llogiq on stuff

Rust in Rhymes II explainer

Update: The talk video is now on YouTube. The slides are here.

As promised, here are some links and explanations to all the rhymes. First of all, the rap lyrics:

My boss said this time I should try a Rust rap
but my rapping skills are positively crap,
Even so, Rust and rapping are a thrilling combination
with which to introduce my talk to RustNation

In London we meet, and the workshops are complete,
so now you people have my talk approaching at full speed,
wakey, wakey, here we are, and I hope you will get
entertainment out of this, or some knowledge instead

Of course I won’t start right away with pages full of code
I’ll start with a few stories, and then switch to teaching mode.
I hope that by the end you’ll know a bit more than before
but otherwise enjoy the show, I’ll try hard not to bore.

I could go on and on about how many talks are lacking
the silliness, the fireworks, just going straight to hacking,
so have some whimsy, have some rhyme, some bars, a little flow
we’re here for having a good time, by golly, HERE WE GO!

In the first bars, we have the very rare self-diss, followed by some flow to announce our whereabouts. Then I go on to establish what I offer in the talk. Again “I’ll try hard not to bore” is a sarcastic self-diss, because of course no one was bored in the slightest. Finally a very tame diss against other talks that lack the entertainment value of this one. After all, I didn’t want to appear too aggressive during a Rust conference. Of course we will have some echoes of this later.

On to the rhymes:

Welcome to this talk, dear Rustacean,
You’re hailing from many a nation,
And you’ve waited some time
for most uplifting rhyme
so let’s start the edification!

A cordial welcome to the audience and setting some expectations for the talk.

Someone from outside London got
his head in my hotel too hot
and the fire alarm
worked this night like a charm
and woke everyone up on the spot.

I would like to have you know that I wrote the rhyme with the fire alarm after experiencing this exact thing: Someone activated the fire alarm in the hotel the RustNation speakers where sleeping in at about 2AM in the morning. So it took a lot of coffee for me to be mostly coherent during the talk.

Since I last talked in rhyme about Rust
I worked in Java and just
three years ago moved
to Rust which behooved
me to go in completely. Or bust.

This is referencing my first “Rust in Rhymes” talk, where after declaring that the talk was about Rust, I showed a Java logo in the second slide as a half-joke. I was actually working in Java during that time.

JFrog, from the name you suppose
they used Java a while, and now those
folks who work to contain
errors in our supply chain
they’re here getting their five lines of prose.

The Rust foundation has teamed up with JFrog to evaluate and improve the crates.io/cargo ecosystem supply chain security. Good for us, I say!

Nowadays I write Rust to help you
getting into Rust code old and new
It will show you the code
and in semantic mode
it will also explain what’s it do.

Please have a look at bloop where we do code search with a semantic twist if you want to know more.

Rust’s steadily been on the rise,
to no Rustacean’s surprise
many people take note
of our bug-antidote
without any speed compromise.

The slide has a google trends chart that shows the Rust community experiencing exponential growth. The rhyme also exhorts the quality of our language which combines correctness with performance without compromising on either.

Rust has now made it on TV
where hackers compiling you see
so join us and write
Rust code with shades by night
if you want as cool as them to be.

I must admit that I found this claim on twitter and didn’t bother to look up the TV show. The slide shows what I presume is a frame of the show that was part of the tweet. Still, it makes for a good rhyme, don’t you think?

Sometimes in Rust you will need
more time ‘til your code is complete
Where in Python you’re “done”
When the code is still wrong
And on perf it’ll never compete.

The slides show two persons, one having solved a puzzle with square pieces incorrectly, while the other is still missing a few pieces for a correctly solved puzzle, alluding to the fact that Rust won’t let you cut any corners with your solution, while dynamically typed languages will be far more lenient, leading to potentially costly bugs later down the road.

There once was a runtime called bun
who thought beating Rust perf was fun.
Rustaceans said “please
bench with dash-dash-release”
Now look at the benchmarks…they’re gone.

The bun javascript runtime written in Zig arrived with a splash, boasting impressive benchmark claims (“faster than Rust!”) that didn’t hold up well to scrutinity (they had compiled the Rust benchmarks in debug mode). Once Rustaceans pointed that out, the benchmarks were quickly removed without further comment.

With Rust and Ada some find
them competing for shares of our mind
Ferrous and AdaCore
thought “we might achieve more
by applying our powers combined!”

Ferrous Systems and AdaCore announced their partnership to promote the use of both Ada and Rust in safety-critical fields like automotive, aerospace, medicine-tech etc. The rhyme celebrates this announcement while arguing for more unity between developers of different language communities.

The Ferrocene scheme will contain
necessary steps to obtain
a Rust certified to
ISO 26262
Let’s hope the effort’s not in vain.

Ferrous Systems announced working on certification of a Rust compiler that will lag behind the most current version and hopefully be allowed to be used in those safety-critical fields where certification is often required by law, bringing safety, performance and productivity benefits to those working with it.

Some functional zealots will tell
that mutation can never go well
but if we never share
what’s mutated, we spare
us from data race debugging hell.

This rhyme notes that in functional programming, you avoid mutation altogether, even if it’s not mutation itself that is the problem, but only the overlap of mutated and shared state. Rust lets us rule out this overlap without the cost of avoiding mutation. This has led some functional purists to decry Rust as inferior, which of course we know is just more gatekeeping.

Some coders will still look in vain
for reasons with C to remain
but “freedom” to crash
is an unholy mash
of stupidity, hubris and pain.

Coming from the other side, the slide cites a redditor who claims to “use C for freedom” and asks others to follow that example. However, the perceived “freedom” here is mostly the freedom to get undefined behavior, as in practice the constraints Rust places upon us do not keep us from writing delight- and useful programs at all. So I’m poking some fun at this really bad take.

Bjarne wants C++ to sprout
some memory safety without
needing more than some lint
Well, good luck, and a hint:
That’s what Rust’s type system is all about.

This alludes to a discussion led by Bjarne Stroustrup, the original creator of C++, who claims they can get the benefit of memory safety with “some additional static checks”, despite the fact that both the Firefox and the Chrome teams tried to make C++ safer and both have turned to Rust now instead. Even with the past showing that this endeavor hasn’t seen much success in the past, I sincerely wish the C++ committee the utmost success in this, as improving the memory safety of a great many programs will be a fantastic boon to our digital security.

The Rust foundation is here
not to mandate, prescribe, boss or steer,
they support from within
Rustaceans for the win,
so let’s everyone give them some cheer!

I wrote this rhyme after talking to Rebecca Rumbul at the foundation stand in the conference lobby, mostly paraphrasing what she said to me. I applaud the work the foundation has done so far, and the audience audibly concurred.

By this time you probably just
have heard elsewhere of This Week in Rust.
I collect crate and quote
and PRs people wrote
for our main source of Rust news you trust.

I couldn’t stop myself from doing some advertisement of one of the community projects I’m involved in, also outlining my engagement with the project.

There was a certain Rust PR
that some folks think went too far
make internal code omit
certain numbers, to wit
in hex they’d fill the swearing jar.

The hex numbers are mostly things like 0xB00B1E5 which is juvenile and doesn’t fit in the professional setting of the standard library documentation. As there is no useful reason to have those numbers in the code whatsoever, the PR in question replaced them with plain consecutive digit ranges like 0x1234 and introduced a tidy check that disallowed re-adding those numbers in the future.

In Rust you will gladly embrace
the compiler’s help if you face
a refactor so hairy
your brain’s feeling airy
It’ll keep track of time, stuff and space.

I’ll get back to the reasons later, but this rhyme airs my feelings towards refactoring in Rust, where the compiler will often be very helpful, often not only showing what needs to be changed, but also how.

We all have learned that a bad
craftsman blamed the tools that they had
but Rust will well teach
us it’s not out of reach
to build far better tooling instead.

Rust’s tooling is top notch in many places. Kudos to the respoective teams. The rhyme still reminds us that the work here is never really done though, and exhorts us to think about how we can improve our tooling even further, then do the work to get there.

For Androids it’s been a must
To be shiny and free of Rust
But to safety’s advance
Google loosened their stance
hoping blue tooths no longer combust.

Some word play here; both for Rust (the language, here mixed up with iron oxide) and Android (the operating system, here taken as a humanoid machine). The last line references the first part of Android that got reimplemented in Rust, which is the bluetooth stack, and the security problems of the previous implementation.

Now in Android version thirteen
there’s more Rust than ever has been.
But now that they wrote
millions Rust lines of code
memory bugs remain to be seen.

I had read a blog post by Jeffrey Vander Stoep, who found that unlike their C++ code, which contained roughly one vulnerability per 1000 lines of code (which by the way makes Android’s code top of the line in the industry), there hasn’t been found any memory safety-related vulnerability in their Rust code so far in more than a million lines of code!

Meanwhile Rust in Linux progressed
to the point where it’s put to the test,
The patch builds the foundation
for the carcination
of drivers. This stuff is the best!

The Rust for Linux patches have been merged into mainline and there are some experimental drivers using it already. Those who have been benchmarked show similar performance to their C counterparts despite not having been thoroughly optimized, which is very promising.

Asahi Lina just took
the GPU of a Macbook
to write drivers in Rust
for Linux, one must
think this is an elite-worthy look.

15 thousand lines of Rust code later
Despite claims from many a hater
Lina’s work here shows
How kernel dev goes
Without any in-GPU crater.

Those two rhymes refer to the M1 GPU drivers project, which has working drivers written in Rust. The author so far has experienced very little problems during the implementation, presumably because of the strong type system and memory safety guarantees the language affords. Contrast this with the development experience of other GPU drivers, which still suffer from frequent crashes and hard to debug memory problems.

When your Rust goes embedded, you’ll find
no need to leave abstractions behind,
with a HAL (not the boor
who won’t open the door)
you get a piece of low-level mind.

I must admit that I’m not that knowledgeable around embedded Rust. That said, I’ve seen some hardware abstraction layers, which offer really nice abstractions on top of the often complex and arcane hardware APIs. The abbreviation of hardware abstraction layer is HAL, which I associated with HAL 9000, the antagonistic AI from Arthur C. Clarke’s “Space Oddyssey” series, who is most certainly the opposite of helpful. The slide for this rhyme shows the famous red camera eye from the 1968 film.

When asked curl in Rust to rewrite
Daniel Stenberg said that he might
But he won’t rearrange
everything in one change
So it sure won’t be done overnight.

Daniel Stenberg, the author of the popular HTTP client tool curl has now introduced Rust into the code base. He’s quite pragmatic with it though, and has so far carefully and considerately introduced Rust.

Rust would be far too arcane
Without Esteban keeping us sane
for the message on error
sparks joy and not terror
though the steep learning curve does remain.

Esteban Küber (I hope that this is the right spelling) is leading the diagnostics working group, which has made rustc produce the most delightful error and warning messages ever known by programmerkind. The rhyme imagines a dystopian alternate reality where Rust error messages would be as incoherent and unhelpful as their counterparts in some other languages’ compiler implementation (although I should note that a rising tide lifts all boats; many of those implementations have improved following Rustc’s example). The final line reminds us that while Rust has gotten far easier to learn in the last 7 years since 1.0.0, we can still improve on that front.

When rustc surprisingly showed
it converts a large int to a float
Mara Bos went complete-
ly berserk for more speed
the compiler’s builtins to demote.

Mara Bos who is leading the libs team and is the author of the phantastic “Rust Atomics and Locks” book, had blogged about a both entertaining and educational story which led her to reimplement the int-to-float conversion routines for Rust’s compiler builtins.

Nyx toolkit brings Rust into space
as other tools they replace
at speed they simulate
how craft accelerate
at this scale you can’t let data race.

Given that the industry sending people into space is usually quite conservative in what tech they use, it was surprising to me to see a Rust application in astrodynamics. Yet here we are.

nushell builds on Rust to be able
to work with data by the table
and letting you pipe
your data with type.
It’s elegant, mighty and stable.

I use nushell as my main shell on windows (haven’t made the switch on Linux yet though), and I find it much more usable than PowerShell.

If your code depends at any rate
on the so-called “rustdecimal” crate
and you also did choose
Gitlab CI to use
Check your systems before it’s too late.

There was a security advisory from the rustsec group. Someone had typosquatted the rust-decimal (note the dash?) crate by copying it and including some malicious code in the build script that installed a backdoor when finding that it ran on GitLab CI.

Rust enums enjoy much attention,
well deserved, so allow me to mention
with match they enable
us to code more stable
and refactor to match our intention.

Here the main joke was the slide which showed an enum Talk { Boring(TechnicalStuff), Interesting(Rhymes) }, echoing the diss from my Rap. The rhyme itself alludes to the fact that we have exhaustiveness checking for matching enums, and so changing them will give us compiler errors at the exact places we need to change to continue our refactor.

Now if you just need a bool
from a match, this macro is cool
unless you must take out
of your type, it’s about
the best match code-size reducing tool.

Having written a good number of if let ... { true } else { false } during my work on clippy, I’m totally happy to have the matches! macro at my disposal, so here it got its well-deserved rhyme. The code on the slide just matches the enum of the previous one.

With traits your code faces ascension
by internal Rust type extension
where you tell everything
how to do anything
so allow me the pay-offs to mention.

This rhyme refers to the power of extension traits which allow us to implement behavior for types defined elsewhere. I wrote this rhyme on short notice after Luciano Mammino’s talk where he spoke about his delight at being able to implement his own iterator methods.

When in Rust code macros you use
I worry a hard way you choose
for debugging it might
become heck of a fight
which means more time later you lose.

I’ve written quite some macros during my work in Rust, and I’m keenly aware that they can make debugging much harder. So here’s a warning to the unwary to think twice if they need a macro for something. Often, generics can do the trick, or the duplication that a macro is built to prevent might be the lesser evil to choose.

In Rust when a thing you mutate
And desire to annotate
that it no longer should
change you easily could
let it be itself until its fate.

This rhyme shows how one can make use of let bindings and shadowing to restrict mutability of a value to a certain area of the code. Keeping values immutable often makes it easier to follow the code, because you don’t have to worry that they change from under your nose. The code on the slide is as follows:

let mut x = get_x();
mutate_x(&mut x);
let x = x;
// x is now immutable

Last time I showed how to break Rust
but this easter egg is now dust,
here’s how out of a scope
you can jump without rope
which is useful and far more robust.

The first two lines reference the RustFest Zurich talk again, which had a rhyme about a Rust easter egg where if you wrote loop { break rust; }, the compiler would output a funny message. Now in the meantime, Rust has allowed break to be used outside loops as a limited form of goto. The slide shows a code example of this:

'scope: { ..
    if broke { break 'scope; }
    ..
}
let result = 'scoop { ..
    if let Some(value) = scoop() {
        break 'scoop value;
    }
    default_value
};

Rust loops come in many a style
but few know it too has a do-while
though its looks may bemuse
you can put it to use
and rest assured it’ll compile.

Again, a funny yet sometimes useful trick where one can emulate a do-while loop using a block in the while condition:

let mut x = 1;
// behold: do-while!
while {
    x += 1;
    x < 10
} {}

Sometimes iterating a Vec
by index incurs a bounds check
however a slice
often won’t, which is nice.
So go get your runtime perf back.

Sergey “Shnatsel” Davidoff wrote a very good blog post on how to avoid bounds checks, which sometimes cost a bit of performance when they appear on the hot code path. The rhyme and code on the slide show the easiest technique, which is using a slice.

Just sometimes a Rust Result looks
like an owl sitting on stacks of books.
With two units as eyes,
on embedded it flies
over meadows and forests and brooks.

This poem is dedicated to the “Owl” result type (Result<(), ()>), which is often used in embedded systems to denote success or failure, where it is far nicer than using a bool while still having the same size.

Rust has special syntax to let
you a function to drop values get
It is named for its looks
toilet closure, the books
tell you to use mem::drop instead.

Another syntax-based poem, this time about the toilet closure (|_|()).

In Febuary a year ago
Rust 1.59 stole the show
with assignments that could
destructure where you would
do multiple ones, now you know.

Rust let bindings use patterns to allow for destructuring, which also afforded them the option to assign multiple bindings via tuples (e.g. let (a, b) = (1, 2)). However, assignments were not awarded this luxury. Rust 1.59.0 finally brought them up to feature parity, so we can write (a, b) = (1, 2); in valid Rust code (given pre-existing mutable bindings of a and b).

One cool byproduct of this option
that has not seen too much adoption
is that you can ignore foo
without let as you do,
it’s a small RSI antitoxin.

A good number of types and functiosn in Rust have the #[must_use] attribute, which the unused_must_use lint will pick up and warn if the result of that functions or return values of that types are left unused. However, as an escape hatch, the lint does not warn if the result is assigned or bound via let _ = ... So you’ll see such wildcard lets from time to time in Rust code. Since assignments now also target patterns, we can simply assign to a wildcard, thus saving the effort of writing let. It will likely be a while until this simplification is widely used.

Rust used to use let but with any
irrefutable bindings, so many
uses where one would guard
the code was somewhat hard
now you get them a dozen a penny.

This rhyme celebrates the advent of let-else, which allows us to use a refutable let as a guard, follwoed by an else block.

Atomics allow you to choose
what ordering on access to use.
While on X-eighty-six
You may easily mix
them, on ARM the results may confuse.

The slide showed a chain link fence. After reciting the rhyme, I asked the attendants: “Know what that is? – A memory fence.”

In Rust you may know that the Range
type does not impl Copy, how strange!
But I’ve heard that some fine
folks hatch plans to combine
their powers this to rearrange.

Many people have noted that Range<T> doesn’t implement Copy even when T does. The reason for this is that historically, Range was defined to be iterable (instead of merely implementing IntoIterator) and copying the iterable would mean that the original would no longer be changed. In the meantime the iterator protocol (how Rust implements a for loop internally) has been overhauled so that this restriction is no longer necessary, but it will probably take another edition to allow us to copy ranges.

Sometimes dyn traits in Rust do require
thinking outside the box to acquire
a solution to track
different types on the stack
to quench our full-stack desire.

I’ve blogged about this before: You can get a &dyn reference to different type without Boxing the values, but you need distinct stack slots for them because a value can only ever have one type.

To many a newbie’s surprise
we often use a str slice
for a lot of stuff
borrowing is enough
and not needing more memory is nice.

This rhyme merely states the fact that when working with strings, borrowing a slice of them often is sufficient.

To defer a task isn’t hard,
in Rust you can just use a guard
which is a type that
does on drop what you had
it in mind to complete from the start.

The slide for this rhyme shows a royal English guard. In Rust, those guard types are really useful, not only for locks.

When a large naïve linked list you drop
your program will crash and then stop
for you’ll exhaust the stack
from there it’s no way back
so please do manual while let-pop.

Alexey Kladow pointed out that the autogenerated Drop implementation would recurse into a singly-linked list (that would be defined by struct Node<T> { value: T, next: Option<Box<Node<T>>> }) in a way that could not be done by tail recursion, so a reference to each node would land on the stack. For large lists, this could overflow the stack. The solution here is to manually follow the list with while let:

impl<T> Drop for Node<T> {
  fn drop(&mut self) {
    while let Some(next) = self.next.take() {
      *self = *next;
    }
  }
}

With Rust, every coder feels safe,
so some venture ever so brave
into OS flaws to
poke some holes into
the cover to then rant and rave.

The slide shows a tweet by Patrick Walton who lamented that it is hard to explain why Rust doesn’t forbid reading from or writing to /proc/mem on Linux (which can be misused to poke holes in our aliasing guarantees). It is generally felt that this is a weakness of the operating system and out of the purview of the language; besides checking this would carry a cost on every file access, which is certainly not proportional to the risk.

When in Rust crates features you use
and don’t ask for docs.rs to choose
to document all
it’s dropping the ball,
as with features it’s somewhat obtuse.

If you want docs.rs to document all your crate’s features, put the following into your Cargo.toml:

[package.metadata.docs.rs]
all-features = true

A cool thing in nightly rust be
called “portable SIMD”,
which means you can say
in a cross-platform way
how instructions should parallel be.

The slides show the following code and output:

#![feature(portable_simd)]
use std::simd::f32x4;
fn main() {
    let x = f32x4::from_array([0., 1., 2., 3.]);
    dbg!(x * 2.)
}
$ rustc +nightly simd.rs -O && simd              
[simd.rs:7] y = [
    0.0,
    2.0,
    4.0,
    6.0,
]

Thus showcasing a simple use for portable SIMD which will work on all CPU architectures (unlike std::arch-based SIMD which is stable on e.g. x86, but bound to that platform).

If your code has the requirement
that a type be not Sync or not Send
it’s time to introduce
a phantom to choose
which type’s contract you will amend.

The slide shows the following code, which defines type aliases for PhantomDatas that, when added to a type, preclude that type being Send or Sync, respectively. This way, Rust allows us to guarantee that values of certain types won’t ever pass or be shared across a thread boundary, which can sometimes be useful for correctness and optimizations.

use std::marker::PhantomData;

type NoSend = PhantomData<*mut u8>;
type NoSync = PhantomData<Cell<u8>>;

struct MyType(usize, NoSend, NoSync);

thread::scope, the first time around
Rust one-zero, alas, was unsound
But if you’re keeping track
you know that it’s back,
this time with correct lifetime bound.

One of Rust’s most impressive features, borrowing across threads, had a problem when it first appeared; it relied on the drop of the JoinGuard actually being called for soundness. So the feature was left unstable in the runup to 1.0.0. Later the crossbeam crate improved on that with its own implementation with a slightly different interface that introduced a lifetime bound into the method’s scope parameter. The standard library even improved on that in Rust version 1.63 by using two different lifetimes, one for the environment and one for the scope.

I told you about Cow last time
but failed to mention in my rhyme
that you can assign-add
change in-place what you had
here as_mut is its partner in crime.

“last time” here is of course referring to the first “Rust in Rhymes” talk I gave at RustFest Zürich. This time, I also returned to Cow (no silly pictures this time, sorry) to showcase its abilities. The slide reads:

// Cow says Moo
let mut cow = Cow::Borrowed("Clone on write");
cow += " makes ownership optional";

cow.as_mut().make_ascii_uppercase();

This code constructs the abbreviated sentence “Clone on Write makes ownership optional” as in “Cow” says “moo”.

Formatting macros now combine
format strings with arguments inline!
Note that this will fail to
work with all things you do
not in local bindings define.

This new feature is really cool; you can write format!("<{foo}>") to put the contents of foo in angly brackets. Unfortunately, rust-analyzer isn’t yet ready to follow references through inline formatting arguments, so it’ll likely be a while until this feature is widely used.

When in Rust async functions you call
they don’t do any work at all
instead they will wait
for you to await
them, this might cause your program to stall

When async Rust was young, many coders fell into the trap of forgetting the .await, leading their async calls to go nowhere. In Rust, calling an async function simply creates the future, but it doesn’t poll it; that’s what awaiting is for. This is in contrast to other languages where simply calling an async function will start executing its code until the first yield or return.

When in Rust async code you borrow
across an await, you reap sorrow
for those two things don’t mix
but with Arc you might fix
your code’s problems until tomorrow.

Another pitfall for new async Rust programmers is that while synchronous Rust is very keen on borrowing, this strategy will fall flat in async Rust. The reason for this is that you no longer control when your code is run, therefore it is impossible to constrain the lifetime of values within your async code. That includes borrowed values, and having something borrowed endlessly is usually a bad idea in Rust.

When a future no longer you need,
and you won’t wait for it to complete,
you drop it, it’s gone
there’s no need to hold on,
and your other code works at full speed.

Cancellation is implemented in idiomatic Rust by dropping the future. Many people still don’t know this and ask how to cancel a future.

Rust hashmaps have some subtle tricks
now throw rustc-hash into the mix
if you do not expect
to be perf-wise attacked
use the hasher it has called Fx.

The Fx hash function is used throughout the Rust compiler. It works very well on integers and short strings, of which there are a great many within the normal lifetime of a Rust compiling session.

When in Rust you’re coding for speed
and write to a file, you will need
to buffer the write
or your system might
wait for every byte to complete.

Continuing our performance theme, this rhyme warns of a performance pitfall that many have experienced: Rust writes (and reads) are by default unbuffered. So you need a BufReader and BufWriter for buffering your reads and writes, lest every IO operation incur far more OS overhead than actually needed.

Likewise it may come as a shock
all your println! calls silently block
on standard out, be aware
if for speed you do care
in that case best use standard out’s lock.

Unlike C, where printf may usually just assume to be able to write on stdout unimpeded, Rust is far more careful, locking the standard output on every write call. You can avoid this by manually calling .lock on io::stdout() and using that locked output.

Those decrying Rust’s unsafe ‘scape hatch
because it “kills all safety”, natch?
Most experts will tell
that it works pretty well
if all invariants you do catch.

Very often in online discussion, people profess or pretend to mistake the unsafe keyword for meaning that the whole idea of safety go out the window. Of course, we know better, and it has even been mathematically proven that safe code can rely on unsafe code as long as the latter upholds its safety invariants.

Some people tell you unsafe will
turn of borrowck and then shill
for C, which is why
they tell this bald lie
because rustc is checking things still.

Another popular myth busted: unsafe allows to work with pointers, which avoid the borrow checker, but it doesn’t turn off the latter.

When in unsafe Rust code you write
and get some things not quite right
it’s no longer the season
for rhyme nor for reason
though your program may run out of spite.

The flipside of all of this is of course that the unsafe code must uphold its invariants come what may. This is often not exactly trivial, and the worst thing about such unsound code is that it may work (“out of spite”) for a good while before finally leading to surprising result come the next compiler version, target architecture or whatever; once UB appears, all bets are off.

The slide for this one is a meme picture showing a crab with the caption “If you put a crab up to your ear, you can hear what it’s like to be attacked by a crab”. The audience loved that one.

Though Rust saves you from a large class
of errors when RAM you amass,
it won’t fix any test
on it’s own, so you best
make sure that each one does pass

This rhyme serves as a humbling reminder that while Rust’s type system and borrow checker will save us from a good set of error classes, it cannot ensure program correctness, so we still need to test. And preferrably also run the tests and make sure they pass.

When rustc with garbage you feed
Don’t fret if the errors you read
Are confusing as hell
The compiler goes: “Well,
I’m telling you straight what 𝐼 need.”

The slide for this shows a @ReductRs tweet reading:

I’m sorry for being so confusing when you were feeding me garbage — Compiler Diagnostics Module Speaks Out.

When secrets you handle in Rust,
deleting them safely you must,
so you don’t get hacked
and your defenses cracked.
The zeroize crate I would trust.

The zeroize crate offers a set of traits you can derive on your types that will make it easy to have data overwritten with 0 bytes when it gets dropped, thus ensuring that e.g. passphrases aren’t lingering in memory for malicious hackers to find them.

Dacquiri: you’d normally think
I was rhyming while having a drink.
But in Rust it describes
A framework to use types
so folks can’t step over the brink

The dacquiri framework allows annotating methods to require certain authorization elements in a way that ensures the implementation cannot be called without authorization.

Andrew Gallant of ripgrep fame
is upping Rust’s byte string game
to make prodding with Rust
real-world data robust
with impressive performance to claim.

This of course refers to the bstr crate.

If a Rust library you change
to avoid things downstream going strange
you can deftly depend
on what future amend
you’re going to pre-re-arrange.

I was cackling about how clever I was when rhyming this (and while choosing the “back to the future” slide), but apparently people in the audience mostly failed to get the reference to David Tolnay’s great semver trick where a crate depends on a future self to implement certain things, thus avoiding incompatibilities between both versions.

If in Rust code you need to parse
some args either dense or sparse
where one went for structopt
this dependency stopped
as now clap pulls it out of its…derives.

The clap crate implements a really great argument parser with many useful features. But the idea to derive the argument parser from a type was born in the structopt crate before being added to clap proper. The last line not rhyming reaped a lot of laughter and applause.

A bevy of games, not of geese
in Rust is a sight that will please
so join in the fun
get some Rust games to run
you’ll find one can do that with ease.

The Bevy engine is a production-ready game engine written in Rust. There is a lot of good documentation, so it’s a great way to get into Rust game programming.

With tauri you stand on the shoulder
of web tech giants, tread bolder
to build quick applications
in all variations
and run them before getting older.

Tauri is a framework that relies on web technology to provide a UI for your application that can still be written in Rust. Relying on the system-native web view, it doesn’t need to bundle an almost-complete Chrome, which makes binaries much smaller compared to e.g. Electron.

When some Rustaceans exercise
their muscles, it’s not very nice,
their squats at any rate
each go on their own crate
so that others need to improvise.

This rhyme laments the sad state of many a crate on crates.io, being a mere shell that has been put there to reserve the name. In consequence, others need to exercise their imagination to come up with a different name. I note that this topic has been discussed to death many times, and there is still no satisfactory solution in sight. So I won’t prescribe one here, I feel that every one that has been suggested so far had flaws large enough to render the idea moot.

We’re surprised to hear cargo test
Is speedwise no longer the best
so I’ll gladly install
nextest, after all
my cores don’t need too much rest.

The cargo nextest subcommand is a new, fast test runner for rust that will often outpace good old cargo test, mostly by maximizing parallelism.

insta will easily check
if the objects your test code gets back
are the same as before
when a good state they bore
so your tests are quickly on track.

Armin Ronacher’s insta crate offers support for snapshot tests, where when you run the test it records the output which you can then save with a subcommand to be compared by future test runs. I cordially recommend it.

From Embark in Stockholm says hi
the subcommand cargo deny
which will thoroughly see
your dependency tree
through for…wow, lots of problems, oh my.

The cargo deny subcommand checks the whole dependency tree for security as well as licensing problems. Suffice to say, I feel much better when it prints nothing upon running it on my code.

Clippy users who at first sense
they’re constantly making amends
To make their code “good”
(as they probably should)
will later become lifelong friends.

cargo clippy now has dash-dash-fix
which changes your code’s subpar schticks
to improve it’s style
and perf, and meanwhile
it has got up it’s sleeve some more tricks.

As a clippy maintainer, of course I had to write a couple of rhymes on it. The first one puts in rhyme a story someone (sorry, I cannot remember who it was) told me that they hated clippy in the beginning, feeling that “it always had something to criticize”, but later were proud and happy that their code was “clippy clean” and now use clippy on all of their code.

The second informs people that many lints now have suggestions that can be automatically applied using the cargo clippy --fix subcommand.

The clippy workshop went great
most people stayed with us late
with good work, much respect,
clippy lints to correct
and also new lints to create

This one I wrote after holding the RustNation-adjacent clippy workshop. My hat’s off to all participants, you are an awesome bunch!

cargo semverver will check
if your current crate version is back-
wards compatible and
warn if change is on hand
that gives users a pain in the neck.

The cargo subcommand has in the meantime been renamed to cargo semver-checks, but the idea is still the same: Giving you advance warning before you introduce changes to your Rust library crate in a minor version that would break your users’ builds. It will likely become part of cargo proper in due time.

Your performance desire to quench
you can put your code on the bench
but to make it complete
a criterion you need
lest measurement errors avenge.

Some people rely on the bencher crate, but I will usually recommend criterion, which has more benchmark configuration options, as well as more solid statistics and optionally a nice graph output.

A helix of Rust can be made
to work on the code you create.
Between entering code
you switch to command mode
with complete & assists, it is great!

The helix editor is a modal text editor like VI that has IDE-like features using the Language Server Protocol (LSP). Unlike VI, it goes selection-first, which takes some time to adapt your muscle memory, but the sleek interface and great performance is well worth it.

With the crypto winter afoot,
Rust jobs are now mostly good
in search, cloud, UI
embedded, AI,
if you haven’t applied yet, you should.

I usually get a few job offers per week. During the late ’10s, most were blockchain job spam. I now get far less of those and more jobs in other fields, which given my stance on blockchain I personally find very pleasant. So if you haven’t sought out a Rust job because you thought it’d all be crypto blockchain web3 stuff, perhaps have another look.

Should I buy an aquarium, my wish
is to fill it with Rust turbofish
One fro, one reverse
(to complete this verse)
& a TV with satellite dish.

I should have put that one to the other syntax rhymes, but somehow failed to do so. Anyway the famed and feared turbofish is a somewhat weird feature of the Rust language that however ensures that Rust code be linearly parseable. The problem it solves is that a < could be the start of generics or a less-than sign. So the fish disambiguates those cases.

Festive Ferris the Crab crossed the street
a bunch of gophers to meet,
and pythons and others
all FFI brothers
to get something to drink and to eat.

This rhyme was a very roundabout way of saying that we programmers are all in the same boat, whether we write Rust, Go, Python or any other language. No programmer is better than another because of what language they choose and we should all strive to improve collectively instead of stupidly fighting among one another.

If you tell people that they must
from now on write all code in Rust
you will earn some ‘aw, shucks’,
for your lobbying sucks.
Good luck on regaining their trust.

In my last Java job before switching my career to Rust, I often felt limited by what I couldn’t express in Java. Yet I knew my colleagues, unlike myself, did not sign up for learning a new language, and forcing them to do so would surely make them hate me. So when you want to introduce Rust at a job, please think of your colleagues who haven’t learned it yet and may not feel the same way about it as you do.

If your thirst for rhymes isn’t quenched
and your love of Rust is entrenched
you’ll find more of my verse
on Twitter – or worse
if that service is tabled – or benched.

I for now have a twitter account where I will sometimes post more Rust rhymes. So if you want to avoid missing any of them, follow me there. The last line alludes to the fact that twitter is steering towards an unknown future since being bought and shedding a great many people. Perhaps I might move to some mastodon instance in the future. Don’t worry, I’ll let all my twitter followers know.

An ML model showed it could rhyme
about Rust in a fraction of time
it does take me to write
a poem, I won’t fight
it ‘cause having more rhymes is sublime.

Well, tickle me pink! I admire,
this work, for now I can retire
and sit on a beach
a stiff drink in my reach.
Why should this AI draw my ire?

The slide for this shows a GPT prompt “Show a rust error message in form of a limerick.” which the model answered with

There once was a code that was fraught
with a borrow checker that thought
“You’re taking a slice, But not paying the price!” And the error message it brought.

I was sent this on twitter with the question if I was worried if the AI would replace me. Why would I be worried? It’s my rhymes and the model’s, not either-or. Besides should I choose to retire, you can still ask the model for more rhymes if you want them.

Farewell now my friends, time to go
I hope you’re enjoying the show
and thank you so much
for you being such
a great audience! Cheerio!

The final rhyme was me being thankful for the great audience (which I had correctly predicted would appear). I can assure you that I wouldn’t have given the rhyme to a lesser audience than this was. A good update to the disclaimer I ended the first “Rust in Rhymes” talk with, don’t you think?

And that’s it. The whole talk explained. I hope you’ve had a good time reading it, and feel free to ask questions on /r/rust if anything is still unclear.