Skip to content
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

"Option definition" is confusing #185234

Open
roberth opened this issue Aug 5, 2022 · 18 comments
Open

"Option definition" is confusing #185234

roberth opened this issue Aug 5, 2022 · 18 comments
Assignees
Labels
0.kind: bug 6.topic: documentation Meta-discussion about documentation and its workflow 6.topic: module system About NixOS module system internals

Comments

@roberth
Copy link
Member

roberth commented Aug 5, 2022

Goal of this issue

Discuss terminology, trying to find an accurate vocabulary for the module system with the goal of improving the documentation and hopefully renaming some terms so that we don't have to rely on the words definition and declaration, which are too close in natural language.

Describe the problem

The module system uses two very similar terms to describe very different concepts:

  • declaration, for the things in options
  • definition, for the things in config (and default and example).

Outside the context of the module system, definition is defined by Merriam-Webster as, among similar meanings:

  • a statement expressing the essential nature of something
  • an act of determining

The first meaning only applies to options, whereas only the second one applies to both.

Steps To Reproduce

Steps to reproduce the behavior:

  1. Be a novice
  2. Use the module system
  3. Be confused by the documentation

Expected behavior

Use clear non-overlapping terminology that doesn't stretch the meaning of non-technical words.

I suggest changing the documentation and error messages to use the term "value" or "option value" where possible. This refers in a correct manner to the relation between types and values.

It is unfortunate that options are declared using Nix language values, specifically those returned by mkOption. However, the term is seems consistent with the options module argument, which contains representations of options that include a value attribute.
Though here, the value refers to the final, merged value, as opposed to the individual "config values" that constitute the final "option value".

Additional context

The module system does not have dedicated user documentation. It has not been exclusively a NixOS component for a long time, and arguably never, by being in lib rather than in nixos.
Do we have an issue for that?
Closest issue I've found:

Notify maintainers

@fricklerhandwerk @infinisil

@roberth roberth added 0.kind: bug 6.topic: documentation Meta-discussion about documentation and its workflow 6.topic: module system About NixOS module system internals labels Aug 5, 2022
@fricklerhandwerk
Copy link
Contributor

I suggest changing the documentation and error messages to use the term "value" or "option value" where possible. This refers in a correct manner to the relation between types and values.

Just to make clear, do you suggest to rename (option) definition to (option) value?

@roberth
Copy link
Member Author

roberth commented Aug 8, 2022

I'm not 100% sure if that's the right thing to do, because right now we have that merging is definitions -> value. By simply renaming, it becomes values -> value, which is inaccurate. A possible solution to this ambiguity is to qualify "value" where relevant. E.g. merging is config values -> option value.

Here's a start for a new vocabulary, including relevant preexisting definitions.

New definitions (as in defining the terminology):

  • config value: values that can occur in the config section, usually excluding the option path (submodules blur this line). Config values can be any of _config value wrapper or any value that conforms to the (shallow) type check function, and they should conform to any further checks imposed by the type merge function.
  • option value: merged values that occur in the module arguments under options.<option path>.value and config.<option path>, constructed by the option type.merge function and optional apply function.
  • config value wrapper: value returned by a config value modifier (TODO: do we have an existing term for this?)
  • config value modifier: mkIf, mkForce, etc
  • definition (possibility 1; we should pick one): ambiguous legacy term; avoid it
  • definition (possibility 2): a combination of option path and either an option declaration, config value, or option value at that location
  • definition (possibility 3): an option path + option declaration

Preexisting (or more obvious?) definitions:

  • config section: the config attribute of a module
  • option path: the attribute path that leads to a mkOption expression, as defined in the options section
  • options section: the options attribute of a module

Known flaws:

  • The config module argument contains option values, not config values. If you know that the module system never exposes config values to modules, this may be ok, but still awkward use of words.

Alternatives:

Use "config" for all "value-level as opposed to type-level-ish" roles:

  • config constituent: config value from "New definitions" above
  • config value: option value from "New definitions" above
  • option value: return value of mkOption. Not really useful, but that's a feature, because config value and option value would be too similar anyway. Avoid.

Any other ideas?

@fricklerhandwerk
Copy link
Contributor

fricklerhandwerk commented Aug 8, 2022

TBH this all looks very confusing. I understand why you did it that way, and I still think it's cursed by knowledge of PLT and implementation details.

What about just saying: option -> option, definition -> configuration?

Then you can define (or better: declare) an option, and define a configuration.

@roberth
Copy link
Member Author

roberth commented Aug 8, 2022

definition (possibility 1)

I intend for us to make a choice what it will be, not to preserve all possibilities here. (will edit)

and I still think it's cursed by knowledge of PLT and implementation details.

This seems to be a side effect of coming up with accurate definitions. I don't see how we can judge the quality of the terminology without diving into all the intricacies. Without doing this, we won't know if we're creating more ambiguities by our renames.

The goal is for the new vocabulary to be more understandable without reading the definitions. The definitions themselves will not be a showcase of how intuitive the new terminology is. That's not their purpose. Their purpose is to avoid ambiguities and serve as reference documentation for the module system itself later.

definition -> configuration

I'm inclined to use the full word configuration for the "sum of all modules" as represented by the example of /etc/nixos/configuration.nix. Ideally we'd have another unambiguous term for this concept (complete configuration? computable configuration? something else?; needs work). It aligns very closely with the other unnamed concept that is the return value of evalModules (and therefore also lib.nixosSystem and friends).

What about just saying

For the purpose of discussing ideas, we can "just say" some renames, but for the purpose of evaluating vocabulary, we need to define them accurately. How would you call the concept I called "config value wrapper" based on your suggestion? Would that be a "configuration wrapper"? To me that seems worse because of the ambiguity with configuration as "sum of all modules", although I admit that discriminating meaning based on whether the word is abbreviated is not really sufficient either. I hope we can do better. I'll ask nbp as well.

@nbp
Copy link
Member

nbp commented Aug 8, 2022

The current naming comes C++ which states that you declare the interface and define the implementation.

Old modules still have a few remnant mentions of it:
https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/printing/cupsd.nix#L124
https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/printing/cupsd.nix#L297

@roberth
Copy link
Member Author

roberth commented Aug 8, 2022

I'm inclined to use the full word configuration for the "sum of all modules" as represented by the example of /etc/nixos/configuration.nix.

We could call this the instance.

  • instance: the result of computing the module fixpoint, the return value of evalModules

Not sure how intuitive that is though, and I don't think we'll stop using "configuration" for the modules that constitute a NixOS instance.
There's a slight collision with AWS EC2 when the two don't exactly line up. E.g. an AMI is derived from one NixOS instance, but in turn produces multiple EC2 instances. Not great, but also not terrible?

@fricklerhandwerk
Copy link
Contributor

@roberth Yeah, sorry for being barely constructive there.

You're absolutely right that we need to first define the things we talk about, and I think you did a great job carving out the concepts in question. Thank you for taking the time! I know this is painstaking work.

Carefully worked through your proposal again, and it fully makes sense to me now. Minor nits, hopefully helpful input:

  • definition possibility 2, appears most intuitive, but I'm not fully convinced yet. Looking from the perspective of how to write prose in this terminology: We can "define a configuration value", but I'd rather "declare an option" instead of "define an option declaration", and as far as I can see there is no "definition of an option value", but maybe something like "the option value is set when/by..."
  • config/option "sections": I know this is pre-existing. Why not call them attributes, as this is what they are? (I remember dimly it was slightly confusing when learning how NixOS modules work, many years ago.)
  • known flaws: what you explained here must be very carefully explained in the manual, then it should be fine.
  • config value vs. option value: I understand the distinction, but does it make a difference for the user? This appears like an implementation detail. I may be wrong here; maybe it's super confusing for people unfamiliar with pure lazy evaluation that setting config values never accesses existing config values but rather option values. I know for a fact it's important to make the distinction to explain how modules work (your elaboration greatly helped strengthen my own mental model), but I guess not that much how to write them.
  • alternatives: config setting (what you define) and config value (what is passed on).
  • result of evalModules: just "configuration". E.g. "... evaluates to a configuration that determines the entire system".

On using abbreviations: I think we should completely avoid them in reference prose, and always write "configuration", while using code tokens such as config as they are. Tokens are just symbols pointing to meaning encoded in programming language, they tend to be arbitrarily terse and obscure. Prose should, as you say in other words, use widely conventional language. Local idioms can be surprisingly steep barriers to entry.

@roberth
Copy link
Member Author

roberth commented Aug 16, 2022

definition

I suppose half of my gripe is the proximity of meaning in natural language. The other half is: suppose I were to ask you:

Define services.postgresql.enable?

Would you say "whether or not the system should run a PostgreSQL database" or false?

"sections" [ -> ] attributes

💯

I guess though in shorthand notation the whole module attrset is a config section. There's a lot not to like about shorthand modules though, but they're easily explained without extra terminology.

config value vs. option value. [...] does it make a difference for the user?

Usually not, but config value may be a good alternative to definition. I agree that often it does not matter. Often a path is good enough: Set services.postgresql.enable to true.

config setting

Conflicts a bit with settings from RFC 42 (semi-structured config file options without necessarily fully declaring everything).
Would have been good.

result of evalModules: just "configuration".

This seems a bit too vague for the purpose of explaining module system features like extendModules.

On using abbreviations

Spot on.
I'd also recommend to avoid them everywhere except small let bindings, but I guess that'd be OT off-topic.

@fricklerhandwerk
Copy link
Contributor

Reviewing NixOS/nix.dev#725 and giving this thread another read, I came to the conclusion that your proposal #185234 (comment) is perfectly workable.

At some point when we get to working on a gentle introduction to the module system, we should approach the config/option distinction by starting with accessing option values through options.<option path>.value to make it perfectly clear, and only then show the shorthand config.<option path>.

@asymmetric
Copy link
Contributor

Reading this, I'm still confused as to what the proposal is for things like "you declare an option like this..." and "you define an option like that".

What are the verbs?

@asymmetric
Copy link
Contributor

Also, in your top-comment @roberth where you say

I suggest changing the documentation and error messages to use the term "value" or "option value" where possible

I think it would be helpful to say /where/ one should use that term, something like

I suggest changing the documentation and error messages to use the term "value" or "option value", where possible, instead of "option definition".

This would clarify your suggestion without having to read all the dense commentary below :)

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-10-26-documentation-team-meeting-notes-89/34668/1

@infinisil
Copy link
Member

Just some brief notes:

  • Let's not bother introducing terms for things we didn't have or need a term before. E.g. we don't have one for "config value wrapper", and I don't think I ever needed it
  • We should definitely have terms for the things we needed terms for before. Notably missing from the proposal here is "option declaration"
  • We should be able to look at a NixOS module and comment the name each of the individuals parts. I'd like to see a proposal formulated in that way, which should make it much more understandable.

@asymmetric
Copy link
Contributor

asymmetric commented Nov 3, 2023

Not sure if anyone still needs convincing that the current naming is unintuitive, but anyway, here's an example that has tripped me up since forever: "The option $x is used but not defined".

For me, defined in this context means the same as declared, unless I've somehow discovered the specific naming scheme the module system uses, which is highly unlikely.

So this is just another data-point in favor of a rename that doesn't use common use terms in a slightly different way.

@asymmetric
Copy link
Contributor

OK, so here's my very simple proposal:

  • A module is declared
  • An option is declared (under options)
  • An option is set (fka defined, under config)
  • No mention of values

The error above would become "The option $x is used but not set".

@fricklerhandwerk
Copy link
Contributor

fricklerhandwerk commented Nov 9, 2023

Discussed in the documentation team meeting:

This needs a PR to the reference docs on the module system, so we have a final state of discussion to iterate on.

A first step would move the relevant bits from the NixOS manual, because they are not specific to NixOS at all.

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-11-09-documentation-team-meeting-notes-93/35244/1

@nixos-discourse
Copy link

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/community-calendar/18589/99

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.kind: bug 6.topic: documentation Meta-discussion about documentation and its workflow 6.topic: module system About NixOS module system internals
Projects
Status: 🏁 Assigned
Development

No branches or pull requests

6 participants