-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib.modules: add mkForAllItems #314058
base: master
Are you sure you want to change the base?
lib.modules: add mkForAllItems #314058
Conversation
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: |
lib/modules.nix
Outdated
also accept a function that takes the attribute name or index (1-based), | ||
the result of which is used as above. | ||
*/ | ||
mkForAllValues = content: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This thread preallocated for bikeshedding the name of this function.
forEach
is used elsewhere in the libraries, but there it means ‘flipped map
’, and this function is not a map at all (if it is given a function, the argument provided to that function is key, not value). So I went with ForAll
to draw the distinction.
Values
splits the difference between Elems
for lists and Attrs
for attrsets, but I'm not wedded to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Items
might be better. Everything except an attribute is already value in the expression language.
types.nix
currently has elemType
in nestedTypes
, which I think was a mistake because item
is a word and elem
is not. (Also elem
is a function in Haskell, fwiw)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to Items
.
/* | ||
For use with options of type `attrsOf *`, `lazyAttrsOf *`, or `listOf *`. | ||
Accepts a value that is merged with every element defined elsewhere. May | ||
also accept a function that takes the attribute name or index (1-based), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This thread preallocated for bikeshedding the choice of 1-based indexing.
I made an arbitrary choice here but AFAIK (not far) Nixpkgs is somewhat incoherent in which of these it uses by default. imap
defaults to 1-indexed (but has explicit imap0
and imap1
options), elemAt
defaults to 0-indexed (and has no elemAt1
alternative). Values displayed to users seem to be 1-indexed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel ambivalent towards this addition.
While it's good to make this functionality more accessible, it introduces more complexity and a performance overhead.
It'd help to quantify that impact.
It might be possible to optimize the common case of no mkForAllValues
.
Not sure how representative this'll be, but I ran this command before and after the patch:
Selected results:
|
```nix | ||
{ | ||
swapDevices = mkForAllValues { | ||
options = mkDefault [ /* ... */ ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
options
is potentially very confusing here. Maybe an alternative example is to change the way home directories are created for all normal users?
That also showcases the parameter, in combination with module parameters, which may also not be obvious how those would interact otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be worried about the home directory example because, as implemented, it uses the value of one attribute in a mkIf
used to compute another. This is doable with mkForAllValues
as well but there is some subtlety to it and I don't want that to distract.
Is the issue with swapDevices.*.options
just the word options
? Can we take swapDevices.*.discardPolicy
instead, or something? Or how about services.wordpress.sites.<name>.uploadsDir
, if we want to showcase the parameter? (I'm leaning toward both.)
|
||
`mkForAllValues` can also accept a function which will receive the element | ||
index (starting at 1) or attribute name for each element or attribute on which | ||
it is used. The result of this function is used as described above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For modules, it the old way with option merging is still relevant. Would be nice to mention here.
it is used. The result of this function is used as described above. | |
it is used. The result of this function is used as described above. | |
If you are extending a submodule with new options, and you wish for its documentation to include your additions, you need a different solution: define the option containing the submodule, as if it didn't already exist, but without `description`. | |
Then the module system will merge the declarations and generate documentation for the combined options. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I don't understand why this is connected to mkForAllValues
. It's always the case that if you want to define a new option you need to declare it. Why is this something that should be explained in this section?
The CPU time and even the GC stats need to be taken with a grain of salt, but the other stats are good proxies for performance. (except concats, which is too specific) I wonder what's the cost of the implicit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found a micro-optimization. I couldn't think of something more significant, except maybe it's worth optimizing the cases where we have no definitions? Only if you're interested in that kind of thing.
9caddb1
to
d376fb3
Compare
Description of changes
For motivation, see Discourse.
For explanation, see additions to nixos/doc/manual/development/option-def.section.md
tl;dr: if you wish you could write (pseudocode)
you can now do that without the dreaded infinite recursion by writing
Is this stupid? Nixpkgs has gotten by this far without it, and there are some alternative patterns available:
Things done
nix.conf
? (See Nix manual)sandbox = relaxed
sandbox = true
nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)Add a 👍 reaction to pull requests you find important.