Evaluation of lib.mkIf vs if then

This is somewhat a related question. Consider the following:

  1. This works
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
  (if virtCfg.virtualbox.enable then "Oracle_VirtualBox_Extension_Pack" else null)
];
  1. this fails (not possible to evaluate unfree pkg) even when the option is set to true
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
    (lib.mkIf virtCfg.virtualbox.enable "Oracle_VirtualBox_Extension_Pack")
  ];
  1. this also works
nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) ([ ]
  ++ (if virtCfg.virtualbox.enable then ["Oracle_VirtualBox_Extension_Pack"] else [])
);
  1. this fails with expected a list but found a set: : { _type = "if"; condition = «thunk»; content = «thunk»; }
nixpkgs.config. allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) ([ ]
  ++ (lib.mkIf virtCfg.virtualbox.enable ["Oracle_VirtualBox_Extension_Pack"])
);

Indeed, lib.mkIf returns a set according to the source.

From what I could understand:

  1. if/else is a Nix lang construct so it’s evaluated before the module system (?)
  2. lib.mkIf returns a set but it’s wrapped inside a function and the module system doesn’t further evaluate (?) so the set doesnt match any name and the package is never allowed.
  3. same as 1
  4. similar to 2 but the concat early fails

This is all due to the difference between what is the Nix Lang and the Nix module system. Am I in the right track?

This is a broad question but I lack enough knowledge to better pose it, when is the module system evaluated in comparison to the language itself?

Pointing documentation/source/blog post is also appreciated.

2 Likes

Yeah, you’ve figured it out!

I made a wiki page about this and related gotchas: The Nix Language versus the NixOS Module System - NixOS Wiki

If that leaves unanswered questions I’d be happy to field them and make it better.

2 Likes

Nice to know about the infinite recursion problem, it’s definitley a gotcha!

So, I assume that the module system it’s only triggered (?) when running nixos scripts such as nixos-rebuild? Somewhere in the callstack there must be a part that interprets the modules arguments of nixosSystem as modules?

lib.modules.evalModules

1 Like

More about evalModules here: NixOS modules: Under the hood.

1 Like