← All posts

The Cost of Having Options

Sep 11, 20265 min read
#linux#wayland#software-design

I was writing a small time tracker. Nothing fancy — just something that watches which window is focused and logs it. On Linux, that sentence is where the trouble starts.

To know what window is focused, you need to talk to the display server or the compositor. On X11, there's a whole protocol for this. On Wayland, there isn't one — it's compositor-specific. Hyprland has its own IPC. Sway has its own. GNOME has its own, and it's not the same as either. So a cross-compatible tracker can't just pick one and compile against it. It has to figure out at runtime what it's running on, then branch.

That's the part I want to talk about. Not the tracker — the branching.

Compile-time vs runtime decisions

When you build for Windows, macOS, and Linux, you usually handle the differences at compile time. The compiler knows which platform it's targeting, so it can drop in the right code and throw the rest away. No wasted work at runtime. You pay for it once, when you build, and then you're done.

Linux doesn't let you do that here, because "Linux" isn't the thing that varies. X11 vs Wayland is the thing that varies. And even within Wayland, Hyprland vs Sway vs GNOME is the thing that varies. You can't know which one you're on until the program is already running on the user's machine.

So the check moves to runtime. Detect the environment, pick a code path, go. It works. It's also slower, more fragile, and more code than any of the individual paths would be on their own.

The tradeoff, stated plainly

If you allow only one way to do something, everything built against it just works. One target, one code path, one set of assumptions. Compatibility is basically free. The cost is that nobody can build a better version, because there's no room for one. If the only way to get a focused window is the X11 protocol, then the X11 protocol is the ceiling. You can't improve on it without breaking everyone.

If you allow many ways, anyone can build a better one. Hyprland can ship its own IPC and be genuinely nicer than what came before. The cost is that every consumer now has to handle all of them, usually at runtime, usually with more code than they wanted to write.

That's the whole tradeoff. It's not a Linux thing specifically — it shows up anywhere a platform decides to be plural instead of singular. It just shows up a lot on Linux, because Linux keeps deciding to be plural.

What this actually costs

The performance hit is real but often small. A branch at startup is cheap. What's not cheap is the shape of the code. Runtime detection means you can't assume anything about your environment, which means defensive checks everywhere, which means more places to be wrong. The bug isn't "the tracker is slow." The bug is "the tracker works on Hyprland and silently does nothing on Sway, and you find out three weeks later."

That's the hidden tax. Not cycles — surface area.

Where the line usually is

In practice, most people writing small tools don't try to support everything. They pick the two or three environments they actually use, branch between those, and let the rest fail loudly. That's usually the right call. Full coverage of every compositor is a maintenance burden that only makes sense if you're building something with a lot of users, or something that's supposed to be a standard.

The interesting case is when a project does try to cover everything. Then you get things like abstraction layers — a single interface that hides all the compositors behind it. Which sounds like the fix, until you notice the abstraction is now the thing everyone has to agree on, and the thing keeping anyone from shipping something better. You've reinvented the single-way problem, one level up.

The part I don't have an answer for

The plural approach is annoying to build against, and it's also the reason Linux has anything good. X11 was the single way for a long time. Wayland exists because someone was allowed to build a better thing, and it took years and it's still messy and it's still worth it.

So the tradeoff isn't really "pick one." It's "decide how much mess you're willing to pay for the chance that someone builds something better." For a hobby tracker, the answer is: not much, support two compositors, move on. For an ecosystem, the answer is: a lot, apparently, forever.

I don't think there's a clean way out of this. The mess is the price of the option. You just have to notice you're paying it, instead of pretending the runtime branch is free.