Describe the bug
Setting a submodule default value to {} does not actually result in an empty set. Setting no default value leads to the option being not defined, but using default = {}; fills the set with attributes declared in its options.
To Reproduce
Minimal example configuration:
# config.nix
{ ... }:
let
extension = { lib, ... }: {
options = with lib; with types; {
users.users = mkOption {
type = attrsOf (submodule {
options.foo = mkOption {
description = "a foo extension for users";
default = {};
type = submodule {
options = { bar = mkOption { type = str; }; };
};
};
});
};
};
};
in
{
imports = [ extension ];
users.users = {
extended = {
foo = { bar = "baz"; };
};
vanilla = {};
};
}
$ nix repl -E 'import <nixpkgs/nixos> { configuration = ./config.nix; }'
nix-repl> config.users.users.extended.foo
{ bar = "baz"; }
nix-repl> config.users.users.vanilla.foo
{ bar = «error: The option `users.users.vanilla.foo.bar' is used but not defined.»; }
Expected behavior
$ nix repl -E 'import <nixpkgs/nixos> { configuration = ./config.nix; }'
nix-repl> config.users.users.extended.foo
{ bar = "baz"; }
nix-repl> config.users.users.vanilla.foo
{ }
Additional context
My use case is to extend users.users.<name> with a new submodule option (here foo), which should only be acted upon if a value is actually set. Following the NixOS manual there is no indication that default = {} will still populate the set. Not setting default does not help either, because there is no (obvious) way to check if a value has been set, since the not defined exception will trigger on evaluation.
Sure, the workaround is to just wrap the submodule in a nullOr type and default = null
mkOption {
description = "a foo extension for users";
default = null;
type = nullOr (submodule {
options = { bar = mkOption { type = str; }; };
});
}
and check for null in the implementation.
This should at least be documented (which it is now, here...), but I'd much prefer that the behavior of default = {} was less surprising. I'd submit a PR but I'd need some hand holding to dig through /lib/modules.nix, because so far I could not find how exactly it comes that the default empty set is not the final value.
Notify maintainers
@infinisil @danbst
Describe the bug
Setting a submodule default value to
{}does not actually result in an empty set. Setting no default value leads to the option being not defined, but usingdefault = {};fills the set with attributes declared in its options.To Reproduce
Minimal example configuration:
Expected behavior
Additional context
My use case is to extend
users.users.<name>with a new submodule option (herefoo), which should only be acted upon if a value is actually set. Following the NixOS manual there is no indication thatdefault = {}will still populate the set. Not settingdefaultdoes not help either, because there is no (obvious) way to check if a value has been set, since thenot definedexception will trigger on evaluation.Sure, the workaround is to just wrap the submodule in a
nullOrtype anddefault = nulland check for
nullin the implementation.This should at least be documented (which it is now, here...), but I'd much prefer that the behavior of
default = {}was less surprising. I'd submit a PR but I'd need some hand holding to dig through/lib/modules.nix, because so far I could not find how exactly it comes that the default empty set is not the final value.Notify maintainers
@infinisil @danbst