Correct way to export Functions in Overlays and use them in others


after watching this talk, i have a question regarding extending pkgs.lib.... in an overlay:

Let’s say i have two overlays from different repos:

# overlay1.nix
final: prev: {
  lib = prev.lib or {} // {
    changeDerivation = drv: drv.overrideAttrs (...); # does "something"
# overlay2.nix
final: prev: {
  foo = prev.callPackage ./foo.nix {};
  foo-changed = prev.lib.changeDerivation;

I am using the variable names final and prev instead of self and super here.

As @nbp states in the talk (simplified):

  • Never use final for anything else than accessing derivations
  • use prev for everything else

… overlay2 only accesses final to access its own package foo.

What feels bad is that i do now have to obey the order that overlay1 must be applied before overlay2, because otherwise prev.lib.changeDerivation doesn’t exist yet.
If it was allowed to use final.lib.changeDerivation, it would (and also actually does) work.

In the Q&A session there were two persons asking a similar question like me, but somehow i don’t really feel like i understand the reasoning behind why using final.lib.bla is wrong.
It would certainly fix the requirement that the order of the overlays is now important…

The reasoning is to be able to strip the fix-point later on. If you are using final to access a function which would later it-self use final, then you are going twice across the fix-point argument.

The fact of going twice across the fix-point argument implies that it would be harder to apply the grafting logic. The grafting logic currently exist theoretically, but there is no better alternative today in terms of implementation.

When the grafting logic would be used, then the same final might represent either the old, the new, or the patched package set. Going multiple time across final implies that a package would skip the patched package set, which implies that the grafting would not be used and that more programs would be considered as replacing the old package set with the new package set.

The reason for this convention is to avoid infinite loops, and to prepare everybody to embrace transparent grafting as a way to apply security updates in the future, by cherry-picking patches of interest without causing the recompilation of the world.