DEV Community

Cover image for Function coloring is real and pretending context propagation isn't infection
Aditya Agarwal
Aditya Agarwal

Posted on

Function coloring is real and pretending context propagation isn't infection

Someone recently attempted to make the bold claim that function color isn't a real phenomenon. Unsurprisingly, the internet had a field day with that.

An essay went viral on this topic, cross-language, bringing Go, Rust, and Zig into the conflict. The argument: coloring is a non-issue conceptually.

Where the term even came from

Bob Nystrom actually first introduced the concept of "function coloring" in February 2015. His article "What Color is Your Function?" described async functions as red and sync functions as blue (even though Nystrom's colors were just made up on the spot and history has shown this to be the correct assignment).

The issue was straightforward. Red and blue do not blend well, and introducing one to the other requires a modification in the higher-ups.

Ron Pressler, tech lead for Java's Project Loom, would later describe this spread as "viral asyncification." Not a flavor of design, a virus.

The Go context detour

This is where it gets interesting. The Go language doesn't use async keywords, so many people believed it avoided the problem of "coloring".

A retrospective of a Causality.blog commented on this very occurrence in April 2026. It said Go "actually introduced a form of coloring through context.Context," since ctx flows through invocations for cancellation.

If you have been using Go since version 1.7, this is familiar to you. Input/output functions require the ctx context.Context as the first argument, and if one function needs it, you must pass it from every caller above.

That's the entire infection process. No keyword needed.

The "it's not real coloring" argument

An essay from September 2026 on Jerf.org is revisited. The essay pushed back on the idea. Its argument was that context.Context is not a color because you can pass context.Background() to stop the spread locally.

I understand the reasoning behind it. It is possible to fix the leak at one location.

But you know what really hurts? It's not the keyword or the type name it's the rewrite you have to do to add ctx to forty functions that never asked for it.

Even if you pass Background() it doesn't reverse it. It simply provides you with a false token to compile the signature. The plumbing remains plumbing. 🔧

What you're doing doesn't matter in a practical sense, since the circumstances will require you to update all callers in the stack. That's the main point, and rephrasing the definition of the term won't change that fact.

What Loom actually proved

Here's the scoop. Java's Project Loom shipped Virtual Threads in Java 21 back in September 2023.

Pressler was talking about avoiding the "method color problem" altogether, not by designing a better context object, but by allowing the runtime to handle the context of a thread.

Consider the implications. If context propagation was just for show, Loom wouldn't have gone to the trouble of having the runtime do it for you.

Years of effort were dedicated to avoiding the need for you to manually thread anything.

Why devs weren't buying it

Perhaps if we rename the illness, the associated symptoms will seem less like our own failings.

However, every developer who has been in the industry for a while has had to do a refactor that is not appreciated. For example, a leaf function that did not require a token, and you had to spend an afternoon passing it through the call tree.

→ Keyword or context object, the infection travels up the stack either way.

→ "You can stop it locally" is true and irrelevant, because the cost lives in the rewrite, not the escape hatch.

→ Loom's existence is the strongest evidence coloring is real pain, not pedantry.

Writing code in Go is different than writing Rust, which is different than writing Zig. But not so different that you think the other one is doing it wrong.

Describing an issue in terms of its functionality doesn't eliminate its impact on an actual codebase. This is what most essays fail to address.

So, my question to you is: Is context.Context in Go a color, a smell, or is it just the tax we pay for cancellation? Where do you draw the line?

Top comments (0)