Avoid rec expresions in nixpkgs?

There are a couple of pitfalls:

  • It’s possible to introduce a hard to debug error infinite recursion when shadowing a variable, the simplest example being rec { b = b; } .
  • combining with overriding logic such as overrideAttrs function in nixpkgs has a suprising behavour of not overriding every reference.

While I agree that rec attrsets suffer from the issues mentioned, I would not migrate back¹ to let expression, at least for things like version.

I would argue that it is quite unlikely that simple attribute like version would cause an infinite recursion – it would be a literal value most of the time. So of the two mentioned problems, only the second one would be relevant here. And while let expression makes it explicit that the value is not overridable when you see the expression, I would expect most people to encounter the issue when calling pkg.overrideAttrs (attrs: { version = "foo"; }) without inspecting the package – that would not work with let either.

Therefore, let expression does not solve either of the aforementioned pitfalls for your example.

There is a pattern that allows using overrideAttrs:

{ stdenv, fetchurl }:
let self = stdenv.mkDerivation {
  pname = "foo";
  version = "1.0";

  src = fetchurl {
    url = "https://foo-${self.version}.tar.gz";
    sha256 = "...";
  };
}; in self

But I am not sure the decreased legibility is worth it. Also it does not currently work with python.pkgs.buildPythonPackage.

Of course, for complex values, narrowly scoped let expressions should be preferred but I would avoid calling rec an antipattern.


¹ We used to define version using let expression quite a lot, but when mkDerivation started accepting pname and version, instead of just name, we started passing them to the derivation directly to reduce verbosity.

13 Likes