Understanding the rationale behind the _:
module convention
I’ve been thinking about the _:
convention for unused module parameters (versus { ... }:
), and I’d love to understand more about its history and rationale. While I appreciate the importance of consistent style in the nix ecosystem, I’m finding it difficult to reconcile some aspects of this particular convention.
My Understanding
The convention suggests using _:
instead of { ... }:
when we’re not using a module’s input parameters. For example:
# Preferred
_: {
programs.git.enable = true;
}
# Discouraged
{ ... }: {
programs.git.enable = true;
}
Questions and Observations
Potential Benefits of _:
- It’s slightly shorter (2 characters fewer).
- It signals “unused parameter” (a pattern seen in some other languages).
- It’s currently the recommended style, ensuring consistency (though I can’t find out why, the purpose of this post).
Some Considerations That Give Me Pause
-
Pattern Consistency
- Nix uses
{ ... }
extensively for argument definitions throughout the language. - Introducing
_
creates a special case that breaks this pattern. - When reading Nix code, we seem to be encouraged to pattern-match on
{ }
for argument definitions, or lack thereof.
- Nix uses
-
Programming Language Conventions
- One justification I’ve seen is that
_
for unused parameters is familiar from other languages. - However, Nix intentionally differs from mainstream languages in many more fundamental ways than this:
- Space-separated function application (
myFunction arg1 arg2
). - Colon-based lambda syntax (
arg1: arg2: arg1 + arg2
). -
let ... in
bindings. - Attribute sets with dot access.
- The
inherit
keyword. - Paths as first-class citizens.
- Space-separated function application (
- Given these intentional differences, optimizing for familiarity in this one case seems inconsistent.
- One justification I’ve seen is that
-
Semantic Clarity
- There seems to be a tradeoff here between two types of explicitness:
-
{ ... }:
explicitly shows the shape of potential module arguments, maintaining visual consistency with other Nix parameter blocks. -
_:
explicitly indicates “I’m intentionally not using any arguments right now.”
-
- This raises an interesting question: in a module system where parameters might be needed later, which form of explicitness is more valuable?
- Is it better to signal “I’m not using these now” (
_:
), or to maintain the visual pattern that reminds readers “these are the standard module parameters” ({ ... }:
) which I haven’t modified?
- There seems to be a tradeoff here between two types of explicitness:
Questions I’d like to understand
- What’s the historical context for this convention? Who introduced it and what problems was it solving?
- Are there technical benefits to
_:
that I’m missing? - Given Nix’s unique syntax in other areas, why was this particular mainstream convention chosen to enforce? Was it maybe part of a wider set of changes that together solved a meta problem?
- Does the code warning about
{ ... }:
over_:
provide enough value to justify the noise it adds to rebuild or development?
I want to emphasize that I’m not suggesting a change of anything—I’m genuinely curious about understanding the reasoning behind this convention. Maybe there are compelling benefits I haven’t considered, or interesting historical context that would help it make more sense to me.
Looking forward to learning from the community’s insights!
PS.
- I have read the Community Guidelines; I believe I comply.
- I’ve also searched for similar topics. Such discussions as -
mkDerivation rec {}
versusmkDerivation (finalAttrs: {})
are on the general theme, but no-one seems to have covered this point explicitly.
I think therefore this post is relevant, but it’s my first post on this forum, so If I’ve failed in complying on either point, it was unintentional … be gentle