Confusing scope difference

Hi there :slight_smile:
While I was writing nix functions to generate a derivation with a s6-rc directory from a definition, I encountered a weird bug when moving a function to a different file:

{ pkgs, ... }:
with pkgs.lib;
{
  func = services:
    something (otherFunc services);
  otherFunc = //...
}

(see real code & error message here - run via nix build .#svcDir)

I then played around until I figured out a weird way to fix it:

{ pkgs, ... }:
with pkgs.lib;
let
  func = services:
    something (otherFunc services);
  otherFunc = //...
in {
  inherit func;
}

(see real code & diff here)

I don’t care about the specific issue, but I’d like to understand what nix concepts I need to learn to understand this? (scopes?)

2 Likes

The issue is regular attribute sets do not introduce a scope, so you get mapAttrsRecursive brought in by with pkgs.lib; statement. Not the one from the attribute set.

If you want a scope, you will need a let…in expression or a recursive attribute set.

I would recommend going through the Language chapter of the Nix manual. At least the data types and language constructs sections – they are pretty short but should give you solid foundations.

In general, I would advise the following: