Nested attribute merging may or may not work as intended
Describe the bug
I would like to be able to say the following:
- A binding to an attribute path
a.b.c = 1;is equivalent toa = { b = { c = 1; }; }; - Bindings with the same name can be combined if both values are attribute set literals (modulo the
reckeyword, maybe)
These two simple rules would explain both the common
{ a.b = 1; a.c = 2; }
# => { a = { b = 1; c = 2; }; }
and the less-common
{ a = { b = 1; }; a = { c = 2; }; }
# => { a = { b = 1; c = 2; }; }
without appealing to additional rules.
This unfortunately fails to hold for deeper attribute paths:
{ a.b.c = 1; a.b.d = 2; } # is okay
{
a = { b = { c = 1; }; };
a = { b = { d = 2; }; };
}
#error: attribute 'b' already defined at «string»:3:9
# at «string»:2:9:
# 1| {
# 2| a = { b = { c = 1; }; };
# | ^
# 3| a = { b = { d = 2; }; };
I don't know if this is a bug (if so, it should be fixable without any breaking changes) or if this is an as-intended aspect of the language that I haven't found a succinct way to describe yet.
Other remarkable comparisons:
{ a.b = { c = 1; }; a.b = { d = 2; }; } # works
{ a = { b.c = 1; }; a = { b.d = 2; }; } # doesn't
{ a = { b = { c = 1; }; }; a.b.d = 2; } # works
{ a.b.c = 1; a = { b = { d = 2; }; }; } # doesn't
Steps To Reproduce
Try to evaluate
{
a = { b = { c = 1; }; };
a = { b = { d = 2; }; };
}
Expected behavior
Same as { a.b.c = 1; a.b.d = 2; }.
nix-env --version output
nix-env (Nix) 2.24.0
Additional context
Knowing whether this is a bug or not is a minor blocker for me writing up a specification of how bindings work as part of #10970. It's fine if it's a bug that hasn't been fixed yet; that can be noted in the documentation. It's also fine if this is how things are supposed to work; I can write the more complicated specification.
Priorities
Add :+1: to issues you find important.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/2024-08-12-nix-team-meeting-minutes-168/50561/1
Discussed during aforementioned Nix maintainers meeting:
The code that handles these syntax combinations is fairly complex and would probably need to be refactored in order to support this properly.
Most of the complexity comes from the combinations with dynamic attributes (${name} = v;)
If supporting this properly proves infeasible, we might deprecate some variations, but not remove it, because they've been supported for around 2 years.
I don't know if this is a bug (if so, it should be fixable without any breaking changes) or if this is an as-intended aspect of the language
These restrictions are not intentional. It used to be that explicit attrsets in repeated attrs could not be merged at all. ~2 years ago we've started supporting that, but apparently the support is not complete.
Perhaps you could document it, but add a caveat that not all combinations are currently supported.
Would you be interested in improving support for these cases?
Would you be interested in improving support for these cases?
I'm interested in taking a stab at it, if the refactoring doesn't prove to be too difficult!
WRT #9020, I assume that you'll want me to keep monstrosities like this working?
nix-repl> { a = rec { b = 1; }; a.c = b + 1; }.a.c
2