tweag / nix-hour

Questions for the weekly Nix Hour
MIT License
78 stars 3 forks source link

NixOS modules and recursion #14

Closed simonrw closed 1 year ago

simonrw commented 1 year ago

I am interested in knowing more about how a nix module can both take and define config properties, e.g.

{ config, lib, ... }:
with lib;

let
  cfg = config.foo.bar;
in

{
  options = {
    foo.bar = {
      enable = mkEnableOption "foo.bar";
    };
  };

  config = mkIf cfg.enable {
    # ... something
  };
}
iFreilicht commented 1 year ago

Just to make sure there's no misunderstandings here: Are you aware that the config at the top is not the same as the config at the bottom?

At the top, it's a function argument. If you rewrote this snippet in something like python, it would look something like this:

def f(config, lib, *args):
  locals().update(lib)  # with lib;
  # let
  cfg = config.foo.bar
  # in
  return {
    'options': {
      'foo': {
        'bar': {
          'enable': mkEnableOption("foo.bar")
        }
      }
    },

    'config': mkIf(cfg.enable)({  """... something""" })
  }

As you can see, the first config is just a function argument. It has no known value until the function is called. The config at the bottom is just one attribute (python: key) of the attribute set (python: dict). There's no recursion going on here.

asymmetric commented 1 year ago

As I think the two concepts are linked, I would love if the explanation of the NixOS module system could explain fixed-points as well :)

infinisil commented 1 year ago

I talked about this in this weeks Nix Hour, feel free to open another issue if you have more questions :)

simonrw commented 1 year ago

Thanks @infinisil for the great explanation. I've just watched the latest episode. Thank you for this series - it's really helped my understanding of nix!