nix icon indicating copy to clipboard operation
nix copied to clipboard

Nested attribute merging may or may not work as intended

Open rhendric opened this issue 1 year ago • 4 comments

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 to a = { b = { c = 1; }; };
  • Bindings with the same name can be combined if both values are attribute set literals (modulo the rec keyword, 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.

rhendric avatar Aug 08 '24 03:08 rhendric

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

nixos-discourse avatar Aug 13 '24 19:08 nixos-discourse

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?

roberth avatar Aug 13 '24 19:08 roberth

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!

rhendric avatar Aug 13 '24 20:08 rhendric

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

rhendric avatar Aug 14 '24 00:08 rhendric