Skip to content

Latest commit

 

History

History
166 lines (124 loc) · 8.3 KB

0110-inherit-as-list.md

File metadata and controls

166 lines (124 loc) · 8.3 KB
Error in user YAML: (<unknown>): found character that cannot start any token while scanning for the next token at line 5 column 16
---
feature: inherit-as-list
start-date: 2021-10-17
author: Ryan Burns (@r-burns)
co-authors: (find a buddy later to help out with the RFC)
shepherd-team: @synthetica9, @infinisil, @kevincox, @bobvanderlinden
shepherd-leader: @kevincox 
related-issues: (will contain links to implementation PRs)
---

Summary

This RFC proposes a new Nix syntax <attrset>.[ <attrnames> ], which constructs a list from the values of an attrset.

The goal is to provide a similarly-terse but more principled alternative to the often-used with <attrset>; [ <attrnames> ].

Motivation

It is currently cumbersome to create a list from the values of an attrset. If one has an attrset attrs and wishes to create a list containing some of its values, one could naively write:

[ attrs.a attrs.b attrs.c ]

To avoid typing attrs many times, one will typically use with instead:

with attrs; [ a b c ]

However, the with expression has many well-known drawbacks, such as unintuitive shadowing behavior [1][2], prevention of static scope checking [3][4], and reduced evaluation performance [3].

Nonetheless, Nix expression authors are subtly guided toward the with form because it is (or at least appears) simpler than any existing alternatives. Some alternatives are suggested in https://nix.dev/recipes/best-practices#with-scopes, but as these are more verbose and complex than with, they are rarely used.

The goal of this RFC is to provide a similarly-terse alternative which avoids these drawbacks.

Detailed design

The proposed syntax is:

attrs.[ a b c ]

This expression is syntactic sugar for:

[ attrs.a attrs.b attrs.c ]

As the token . immediately preceding [ is currently a syntax error, a Nix interpreter which supports this new language feature will be compatible with existing Nix code.

This RFC is implemented here: NixOS/nix#5402

For MVP functionality, only minor additions to src/libexpr/parser.y are needed. If accepted, the changes to the Nix interpreter can be backported to current releases if desired. Relevant language documentation and third-party parsers/linters would also need to be updated.

Examples and Interactions

This would be useful for many languages and frameworks in Nixpkgs which extract packages from a package set argument.

For example, python3.withPackages (ps: ps.[ ... ]) will serve as a more fine-grained alternative to python3.withPackages (ps: with ps; [ ... ]). This would apply similarly to vim.withPlugins, lua.withPackages, etc.

Certain list-typed meta fields could also make use of this feature, e.g.:

meta.licenses = lib.licenses.[ bsd3 mit ];
meta.maintainers = lib.maintainers.[ johndoe janedoe ];

Note that only simple textual attrnames are allowed in the square brackets. For example, pkgs.[ (openssl.overrideAttrs { patches = [ ... ]; }) ] is currently a syntax error, as is pkgs.[ "${some_expression}" ], a.[ b.[ c d ] ], and a.[ [ b c ] [ d e ] ]. Future RFCs may add additional support for useful idioms such as pkgs.[ python310 python310Packages.pytorch ] on a case-by-case basis, but that is not planned for this RFC.

For a comparison of other forms of syntax considered but not proposed in this RFC, refer to the Alternatives section.

Drawbacks

  • This will add complexity to the Nix grammar and any third-party tools which operate on Nix expressions.
  • Expressions reliant on the new syntax will be incompatible with Nix versions prior to the introduction of this feature.

Alternatives

A number of alternatives have been considered, which can be roughly divided into syntactic (introducing new syntax which requires changes to the Nix language to parse) and non-syntactic.

Comparison of syntactic alternatives:

Priority is given to syntax which would be "backwards compatible" with existing Nix code, meaning that any existing code would be evaluated the same under an interpreter supporting the new syntax. Conversely, evaluating new code under an old interpreter which does not support the new syntax would cause a syntax error.

Syntax Notes Cons
inherit (attrs) [ a b c ] Initial draft "confusing that for attribute sets, the inherit keyword is on the inside but here it is on the outside" -jtojnar
[ inherit (attrs) a b c; ] 2nd draft, proposed by jtojnar "not very happy with reusing inherit here. If I read inherit I read 'right, an attribute-set'." -Ma27
"There currently is no separator in lists, and this would add that." -Synthetica9
attrs.[a b c] 3rd (current) draft, proposed by Synthetica9 Has "ambiguities [...] which would have to be worked out" -Synthetica9
"what [a b c] means depends on if it is after attrs." -kevincox
Needs care to limit scope of this rule, currently limited to single-identifier case (discussions here and here)
[ with attrs | a b c ] Proposed by nrdxp "Looks more foreign", "may also cause confusion with other languages" -kevincox
"introduces a small inconsistency" vs attribute-set inherit -rehno-lindeque
Exclusive with, let with Proposed by infinisil and later refined Requires some dynamic behavior to fully replace with, including nested usage -oxalica, -infinisil
May change semantics of existing Nix code

Some common threads here are the desire to introduce a syntax form which is simpler and more ergonomic than existing with or alternatives, naturally guiding users toward a "safer" form. We also desire consistency, reusing keywords or syntax patterns but only where it would be harmonious with the existing Nix language.

Comparison of non-syntactic alternatives:

Other alternatives have been proposed where the motivation for with deprecation is acknowledged, but would be resolved without introducing new syntax to the Nix language.

Alternative Notes Cons
builtins.attrValues { inherit (attrs) a b c; } Considered in initial draft Verbose, cumbersome to compose, not order-preserving
select [ "a" "b" "c" ] attrs Proposed by ocharles "highlights wrong (strings are not data but literal variable names)" -7c6f434c
"with is slightly more ergonomic", "the proposed change is arguably same [...] but without semantical gotchas" -7c6f434c
Deprecation of list-types in NixOS modules and build inputs Proposed by infinisil "order of buildInputs is significant so unordered sets cannot be used" -jtojnar

Unresolved questions

How would this feature be adopted, if accepted?

Future work

Determine best practices regarding when this language construct should be used