NixOS / nix

Nix, the purely functional package manager
https://nixos.org/
GNU Lesser General Public License v2.1
11.45k stars 1.44k forks source link

Add attrpath notation equivalent to `elemAt` #10949

Open rhendric opened 1 week ago

rhendric commented 1 week ago

Is your feature request related to a problem? Please describe.

I'm in a REPL. I'm exploring parts of Nixpkgs. I type a partial expression:

nix-repl> someExpr.foo
{ bar = { ... }; ignoreThis = { ... }; moreStuff = { ... }; }

I hit up-arrow and keep typing to drill deeper:

nix-repl> someExpr.foo.bar
{ baz = true; qux = [ ... ]; quux = { ... }; }

nix-repl> someExpr.foo.bar.qux
[ { ... } ]

nix-repl> someExpr.foo.bar.qux.0
error: attempt to call something which is not a function but a list

       at «string»:1:1:

            1| someExpr.foo.bar.qux.0
             | ^

Of course that doesn't work. I don't actually type that. What I actually do is hit up-arrow, then hit Home, then type builtins.elemAt, then hit End, then type 0.

nix-repl> builtins.elemAt someExpr.foo.bar.qux 0
{ greatMoreStuff = { ... }; }

Now what do I get to do? That's right, hit up-arrow, then hit Home, then type (, then hit End, then type ).greatMoreStuff.

It's a tiny papercut of a problem, but it makes me die a little every time I see a list in a complicated Nix expression. In many other languages with left-to-right dotted accessor syntax, I'd be able to write someExpr.foo.bar.qux[0].greatMoreStuff, or someExpr.foo.bar.qux.0.greatMoreStuff. Why not in Nix?

Describe the solution you'd like

I'd like the Nix attrpath grammar rule to be extended with some notation that's equivalent to builtins.elemAt, such as attrpath.0, attrpath[0], attrpath@0 if you like—any available syntax is fine with me as long as the result is still an attrpath, and thus can be extended with more attribute selectors without enclosing the entire previous base expression plus attrpath in parentheses the way that (builtins.elemAt ... 0).greatMoreStuff requires. I would even be happy with reusing the existing syntax attrpath.${0} and supporting integers applied to lists with that in addition to strings applied to attrsets.

Describe alternatives you've considered

Not caring about the tiny details that make Nix uncomfortable relative to other languages.

Additional context

I imagine this needs an RFC, given https://github.com/NixOS/rfcs/pull/148, but I wanted to float this here first to see if there's an instant hell-no.

Priorities

Add :+1: to issues you find important.

roberth commented 2 days ago

I personally think the cost benefit works out slightly in favor of having this feature. It's rare to need elemAt, and most functions should not use it, but it's useful in the repl.

We don't get to change usable syntax (perhaps until https://github.com/NixOS/rfcs/pull/137), so we don't have a lot of choice.

attrpath.0

Unfortunately, this is equivalent to attrpath .0, a function application with argument 0.0.

attrpath[0]

Same, but with a list.

attrpath@0

Currently an @ always creates a binding. I'd like to reserve it for that purpose.

attrpath.${0}

This would make type inference worse (e.g. in https://github.com/oxalica/nil), as the lhs can be a list or attribute set, and the rhs can be an int or string. Also the property that the types need to match up may be hard to express in a type system.

How about...

It being distinct makes type inference easy, and helps readers.

[ reminds of lists, and $[ is still available as far as the grammar's concerned.