That works for the kernel. But if you have to patch, say, glibc, under Nix doesn't that mean you can no longer use precompiled binaries, and have to recompile every single package that uses libc, from source?
Sure, it still works. And in the off-chance that you need to make a patch that changes the ABI, recompiling the world is exactly what you want. But usually you don't need to change the ABI (at least not in a backwards-incompatible way), and recompiling the world can take a very long time.
Another way to address this concern. Nix allows you to specify what you want to do in this case. You can either:
1) Decide you want that patch to be applied to everything, resulting in recompiling the world.
2) Apply the patch for only the specific project you are working on/testing/etc. Thus only that thing is recompiled.
3) You can cheat in various ways if your project truly requires being updated by only changing the glibc and no recompilation is feasible. Some options: the way OpenGL and graphics is currently done in NixOS, nix-rewrite (https://github.com/timjrd/nixrewrite), and LD_PRELOAD. Breaking the abstraction in this way may have practical benefits, but you also lose the reproducibility and excellent bookkeeping of all the details that Nix provides.
4) specify a container/project/VM that uses your patched glibc, so only those things are rebuilt that matter in your use-case.
The crux of the matter is that we need to be more precise in the names of things. Most of the time "glibc" refers to whatever is on your system on the same path. Nix has taken the other extreme where you can't just say "glibc", you really mean "this particular source, compiled with this particular set of flags and build script". If you want something more powerful\and between those extremes, there is some work currently on a system called Nomia that attempts to provide a far richer naming semantics, but it is still experimental. https://github.com/scarf-sh/nomia It would allow something like "glibc means anything ABI compatible with this particular thing, plus some other requirements...."
This may change in the future with Nix moving to a content addressable store.
I lack the technical know how behind it, but if the output of a package doesn't change on changing one of the inputs then nix will not rebuild it's cache.
If you're patching glibc, most of the time, you're going to change its output. Determining whether you need to redo downstream builds based on changed outputs is great if the thing you're changing is docs or optional libraries (such that most packages don't have a dependency on the thing being changed), but it doesn't help with patching the core.
The interesting case would be if you build separate build-time and runtime interfaces - like a libc.so that just has dummy symbols for everything that it defines but no actual implementations, and a libc.so.6 with the actual implementations that can change.
While most Linux distributions have the split of filenames, it's not actually done in this way - libc.so is a symlink to libc.so.6 (or in the specific case of glibc, a linker script), so it requires the actual libc.so.6 to be around and used during the build.
It would also be a bit of a semantic change in how Nix operates, as I understand it: currently you can run ./configure scripts that detect the behavior of libraries by actually running code, and if that behavior changes, Nix guarantees a rebuild. If you remove runtime libraries from what's visible during the build, you can't run such scripts anymore (or you're running them against a version of the library that doesn't trigger rebuilds when it changes).
Nix has a facility for patching libraries without recompiling the world (the intended use case was for novel zero-days where waiting for hydra to rebuild the world was unacceptable). All I know about it is that I've heard it exists though.
Sure, it still works. And in the off-chance that you need to make a patch that changes the ABI, recompiling the world is exactly what you want. But usually you don't need to change the ABI (at least not in a backwards-incompatible way), and recompiling the world can take a very long time.