Apart from being a Haskell advocate, Tobias is also a Nix advocate, which seem to go hand in hand, according to my quick survey of google results mentioning both Haskell and Nix. So, just like I’m learning Haskell, it seemed logical that I start looking into Nix as well. After all, if he wasn’t wrong with Haskell, there’s a high chance he’s not wrong with Nix either, right?
That’s how we got here, to me writing about Nix, after just one day of being really exposed to it. I do this because in the past 70 days, I’ve found that writing about a topic helps me straighten my ideas about it. Here goes.
What’s a Nix and how do I eat it
If you go here, you’ll read that Nix is the Purely Functional Package Manager. Of course, if you’re like me and you’ve mostly npm’d your way through life with a sprinkle of maven on top, you probably didn’t even know that package managers could be purely functional. I hadn’t even stop to think that the ones I had been using so far weren’t purely functional, so you’ll see how that can be confusing. Let’s unpack that sentence first:
- Functional ➡ means it works by using functions, in the sense that everything takes an input and delivers an output.
- Purely ➡ purity happens when a function yields the same result, given the same input. That makes it so that pure functions can always be reduced to a simple value, and more importantly, the result of a function can be safely saved once it’s been used, since it won’t change unless the input changes. Very cool stuff.
So, a Purely Functional Package Manager is a package manager where everything is a pure function.
In Nix, packages are handled through something they call Derivations. A derivation is a set of instructions and data necessary to build and install the package. Each derivation is a pure function, and as such will always yield the same output. The way it manages to do this, as far as I understand it is because:
- It always starts fresh. No
PATHvariables, no pre-installed packages, no nothing. Only what’s specified in the derivation will be installed.
- It contains all the dependencies for that package, which in turn are also a set of derivations which also have all their dependencies… you get the idea.
- Every derivation will have the same result, so every dependency for the package will be the same every time, same as the package itself.
- It will all be self contained inside a folder called the nix-store, and made unique by creating a hash built from all the code necessary for the package. So, if one character of the package changes, then that hash will change, forcing the system to create a new derivation (not change the older one).
What that means in practice, is that you end up with a lot of paths that look like
/nix/store/qpowierupzxcvp24qrkwrsdfa-hellopackage. And each one contains the instructions for an entire package, with dependencies, build steps and whatnot. So, every version of
hellopackage will be its own derivation, with its own unique path. Same goes for every dependency, so you know every time you build
hellopackage it will grab the same code for the same dependencies, regardless of wether you have different versions of the dependency in your
nix-store. And that’s also something it can do, handle multiple versions of the same dependency seamlessly, since each one is unique. It’s like it was a different package altogether.
Why should I care?
Because certainty is good. And being certain that your package will always work, regardless of where you try to use it is really, really good. Also, having only one dependency for your projects sounds amazing. All of us have been in the position of getting to a new job, getting a new laptop and having to go through a 12 page document on how to set your development environment up, including downloading and installing 10 different dependencies globally, that may or may not have changed drastically since the time the guide was written.
With Nix, you could get the laptop, install nix and use it to build projects immediately. It would take care of that 12 page document for you, ultimately saving time for you who won’t have to go through the guide, and your team that won’t have to constantly try and figure out why it’s not working on your machine.
So, so far so good. Nix seems like a good thing, meaning Tobias wasn’t wrong. The actual code part does seem a bit complex, and the documentation is too complex to understand in one go, but maybe it’s a complex tool that warrants having complex documentation. Maybe not. We’ll find out for sure though.