-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
lib: Add beforeApply option attribute #302905
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -807,6 +807,9 @@ let | |
|
|
||
| in warnDeprecation opt // | ||
| { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value; | ||
| # The merged value before applying the options `apply` function to it. | ||
| # In general though, `apply` should not be used, it's an anti-pattern. | ||
| beforeApply = res.mergedValue; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another angle is the current impossibility of using #257511 to simplify
What if
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds interesting, though I don't think having Once we deprecate
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think |
||
| inherit (res.defsFinal') highestPrio; | ||
| definitions = map (def: def.value) res.defsFinal; | ||
| files = map (def: def.file) res.defsFinal; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { options, lib, ... }: | ||
|
|
||
| # Tests wheter a apply function properly generates the `beforeApply` option attribute | ||
|
|
||
| { | ||
| options = { | ||
| optionWithoutApply = lib.mkOption { | ||
| default = false; | ||
| type = lib.types.bool; | ||
| }; | ||
|
|
||
| optionWithApply = lib.mkOption { | ||
| default = false; | ||
| type = lib.types.bool; | ||
| apply = x: !x; | ||
| }; | ||
|
|
||
| okChecks = lib.mkOption {}; | ||
| }; | ||
| config.okChecks = builtins.addErrorContext "while evaluating the assertions" ( | ||
| assert options.optionWithoutApply.beforeApply == options.optionWithoutApply.value; | ||
| assert options.optionWithApply.beforeApply == !options.optionWithApply.value; | ||
| true); | ||
| } |
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 adds the cost of a whole attribute to every option, but delivers almost no value in almost all cases.
Also it doesn't fully solve the problem. What if
opt.beforeApplyis wrong, and a non-trivial number of modules relies onopt.beforeApply?mkOption { modifyBeforeApply = f; }?opt.beforeModifyApply?I think at some point we just have to admit that modules aren't fit for certain options or option trees anymore.
What if instead of an option tree or
submodule, we could have atypes.adapter, which transforms all definitions arbitrarily, transforms the returnedconfigandoptionsarbitrarily, and can be implemented in whichever way the use case demands?That way we don't have to further bloat the module system with mostly unnecessary attributes, and actually do a better job at being compatible.
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.
Not sure what you mean by that?
It only makes sense to rely on
beforeApplyif the option has anapply, otherwise it's the same as the optionsvalue. Andapplyis being discouraged already, you won't find much new uses. The main use case here really is just allowing certain reasonable configs for older options that already useapplyand can't be migrated away from easily.I agree that it's a high cost to pay for very little value though..
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 is also a good time to mention #299736 as an alternative implementation that doesn't add a new attribute to all 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.
This time
opt.valueis wrong. Next timeopt.beforeApplyis wrong. Why would this sequence stop?I'm not convinced of 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.
opt.valueis "wrong" this time becauseapplyexists, so we needbeforeApply. The sequence stops here because we don't have a "pre-apply" step. After the values get merged, it gets passed toapplydirectly.At least I'm heavily discouraging
applywhenever I see 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.
Hmm, I might have overreacted.
Bloat argument still stands though, or are we betting on replacing
evalModulesin the foreseeable future?I like the idea of having time to do that... :)