-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
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.lazyFunction: init #194514
base: master
Are you sure you want to change the base?
lib.lazyFunction: init #194514
Conversation
ab40581
to
d0e5b4e
Compare
lib/trivial.nix
Outdated
@@ -467,6 +471,41 @@ rec { | |||
then v | |||
else k: v; | |||
|
|||
/* | |||
Make a function lazy in its arguments. |
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.
Make a function lazy in its arguments. | |
Make a function lazy in its argument. |
I don't like how this detail matters, but it does because there's only one actual argument here, the destructuring only makes it seem like multiple arguments. And lazy in arguments could be interpreted as making the attribute values lazy instead of strict (but that part is always lazy)
can return a the (partially evaluated) function body (`{ r = ...; }`). | ||
|
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.
can return a the (partially evaluated) function body (`{ r = ...; }`). | |
can return a the (partially evaluated) function body (`{ r = ...; }`). | |
`lazyFunction` can change such a function to not evaluate the attribute | |
names of the argument before the body is returned. | |
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've rewritten a lot to make better use of the example instead.
lib/trivial.nix
Outdated
`lazyFunction` uses reflection on the passed in function and it only works | ||
for functions defined with a "set pattern". |
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.
It using reflection (which is not really a known term) is an implementation detail, can be omitted. And the note about it only working with set patterns should be moved down.
`lazyFunction` uses reflection on the passed in function and it only works | |
for functions defined with a "set pattern". |
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 think it's relevant because using reflection breaks the function abstraction, which is a big deal.
I've removed it for now, because I agree describing the consequences is more important.
lib/trivial.nix
Outdated
It makes a function like `{ a, b }: { r = foo a b; }` behave like | ||
`args: { r = foo args.a args.b; }`. |
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.
It makes a function like `{ a, b }: { r = foo a b; }` behave like | |
`args: { r = foo args.a args.b; }`. | |
In other words, it makes a function like `{ a, b }: { r = foo a b; }` behave like | |
`args: { r = foo args.a args.b; }` instead. |
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've changed this to show the "generated wrapper" instead. I think that helps more with understanding.
lib/trivial.nix
Outdated
It is not compatible with ellipsis patterns, `{ ... }:`, because only the | ||
explicitly declared parameters are passed through. For example, the | ||
following will not work: `lazyFunction(args@{ a, ... }: args.b)`; | ||
even if the caller provides `b`. | ||
|
||
It also removes the checks against unexpected arguments. |
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.
It is not compatible with ellipsis patterns, `{ ... }:`, because only the | |
explicitly declared parameters are passed through. For example, the | |
following will not work: `lazyFunction(args@{ a, ... }: args.b)`; | |
even if the caller provides `b`. | |
It also removes the checks against unexpected arguments. | |
This function has some limitations: | |
- It doesn't work for functions that don't do attribute destructuring like `arg: { r = foo arg.a arg.b; }` (`a`/`b` wouldn't be accessible) | |
- It doesn't work for functions with ellipses (`...`) like `arg@{ a, ... }: { r = foo a arg.b; }` (`b` wouldn't be accessible) | |
- It removes checks against unexpected arguments, so `lazyFunction ({ a }: a) { a = "a"; b = "b"; }` doesn't give an error. |
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'm just calling it attribute destructuring here instead of "set pattern", because nobody calls it that
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.
Somewhat jokingly I wrote #194992, which could check for some of these limitations in the code itself
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.
An author of the Nix manual uses this term.
(functionArgs f) | ||
) | ||
) | ||
(functionArgs f) ; |
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.
We could try to prevent some misuse by throwing an error when functionArgs f
is {}
, but that might not be worthwhile.
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.
That could be a problem if someone uses lazyFunction
to construct another function where constant functions are a valid argument.
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.
Super bad example, but better than no example?
let
testCase.foo = { a }: a * 2 == a + a;
testCase.bar = { }: true;
in mapAttrs (k: lazyFunction) testCase
Description of changes
Adds a function that makes attrset-matching functions lazy using reflection.
This is similar to what the module system does for module arguments, but not powerful enough to abstract that.
This isn't used in nixpkgs yet, but may be used in #193336; however, I'd like for this to be reviewed separately.
Things done
sandbox = true
set innix.conf
? (See Nix manual)nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"
. Note: all changes have to be committed, also see nixpkgs-review usage./result/bin/
)nixos/doc/manual/md-to-db.sh
to update generated release notescc @infinisil