nix-language-more.md

Set shorthand

Before this, you'll want

  1. The Great Rebuild
The Nix language13 min

You can already read values, sets, and functions. That is most of Nix.

Open a real flake.nix anyway and it can still look alien, because working Nix leans on three shortcuts you have not met. All three exist for the same reason: Nix hates repetition. None of them changes what an attribute set actually is.

inherit copies a name in

Writing name = name; feels silly, and Nix agrees with you. inherit grabs a name from the surrounding scope and drops it into the set under that same name.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

Hover inherit and you’ll see the same set written out the long way.

One inherit will take as many names as you throw at it, the way inherit a b c; does.

Try it

Bring the shell across as well.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

inherit can name where from

Put a set in brackets and the names come out of that set instead of the surrounding scope.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

Read inherit (user) name; as “take name, from user”. It is precisely the same as writing name = user.name;, which is exactly what the hover will tell you.

This form takes several names too: inherit (user) a b;.

Try it

Take the shell from the user too, and leave the port behind.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

Get comfortable with this one. It turns up constantly in package files, where a handful of names get picked out of a much larger set.

rec lets a set see itself

Imagine you want to reuse a set value inside itself. A normal set cannot use its own names, because those names only exist for whoever ends up holding the finished set. Which is why this needs a let sitting above it:

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

rec cuts out the middleman. The set becomes recursive, and any value inside it may use any name inside it.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

Order still doesn’t matter, because Nix is lazy.

Try it

Ship version 2.0, and let the name follow on its own.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

You changed one value and two of them moved. That is the appeal, and it is also exactly why a large rec set gets so hard to follow.

// puts one set on top of another

// hands back the left set with the right set laid over the top of it. Wherever both name the same attribute, the right side wins.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

This is how “sensible defaults, plus my changes” gets spelled in Nix.

Try it

Change the host to example.com.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

That went through, because nothing on the right had an opinion about host.

Now try changing port in defaults as well. Set it to 9000 and watch the result flatly refuse to move: the right side already claimed port, so the right side keeps it.

Editing a default that something further along quietly overrides is a very ordinary afternoon in Nix, and now you know what it feels like from the inside.

There is one more thing about // worth carrying with you. It only merges the top level, so a nested set on the right replaces the matching one on the left outright instead of blending into it.

nix replevaluated as you typeNixA plain Nix expression. Nothing from nixpkgs or a module system is supplied.

The host is gone. The whole service set got replaced, not updated.

If you are now wondering how a NixOS configuration combines nested settings from a dozen files without losing things like that, the answer is that it doesn’t use // at all. The module system merges one option at a time, and the option’s own type is what decides how. The modules lesson is where that gets taken apart.

What to keep

  • inherit name; is name = name;, and inherit (set) name; is name = set.name;.
  • rec { } lets a set’s values use the set’s own names.
  • a // b lays b over a, at the top level only.

Each of these carries a real rule about scope, recursion, or replacement. Knowing the longhand sitting behind them beats memorising the punctuation every time.

Useful links

NORMALCOURSE IN BETA