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
Improved submodule name
passing
#97378
Conversation
3744a37
to
bbf6d96
Compare
This looks alright. I really like the "stack" approach of having the innermost name first. Perhaps this could be reflected in the name, like I'm also wondering about lists. I'm not actually a big fan of those, but perhaps it's useful to include list indices in it? Not sure what the name should be in that case. |
bbf6d96
to
16b35bf
Compare
@roberth I like the suggestion of calling it I think using a list like that is fine for now. |
16b35bf
to
dcc0b20
Compare
@roberth You think this is looking good now? If there aren't any complaints I'll merge 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.
I'd prefer to read modules where information like name
is passed down into submodules via the lexical scope, so I don't think we should recommend using this with list indexing operations like . I had to look that one up; don't think I've used it before and for good reason. List indexes have no meaning by themselves and can always be avoided by using high-level list operations like elemAt
concatMap
and whatnot, unless you're not managing configuration but implementing clever algorithms which is an entirely separate domain for which the module system is unfit. /rant
tl;dr name things, don't number things. Simple lexical scoping is one of the nicest things in functional programming, so let's use it.
Still I think this feature could be useful for some generic purpose. Did you have something like that in mind?
# For backwards compatibility, expose the most relevant name | ||
# directly |
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 backwards compatibility, expose the most relevant name | |
# directly | |
# Conveniently expose the most relevant name directly |
This is the most used one, so let's keep it around.
I marked this as stale due to inactivity. → More info |
@roberth But what would the name be? We can't name things without names! There's no inherent naming for the level of submodule recursion |
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.
Without a compelling use case, I am not convinced that nameStack
is better than passing outer names to inner modules via lexical scope.
The module author can choose their own names. |
@roberth The problem is that there's no naming of these values defined. To do this you'd have to e.g. extend the definition of attrsOf {
metaName = "myName";
elemType = ...;
} This would then allow you to access { names, ... }: {
result = names.myName;
} I'm also not convinced that this specific PR is a good idea, but I'm also not sure how else it could be done nicer. |
This is an improvement, but I don't think it's necessary. { name, ... }:
let virtualHostName = name;
in {
options.locations = mkOption {
type = submodule ({ name }:
let locationName = name;
in {
config.baseUrl = lib.mkDefault "${virtualHostName}/${locationName}";
});
};
} Granted, this does not work for directly nested |
Hm yeah fair enough, let's not do this then. |
Motivation for this change
Submodules receive the
name
argument which tells them which attribute they are defined under. E.g.This makes the
foo
option evaluate to{ bar = { name = "bar"; }; }
However there are also some problems with this, namely (hah):
If the submodule isn't defined under an
attrsOf
, thename
isn't relevant at all. E.g.makes the
foo
option evaluate to{ name = "foo"; }
. This isn't useful at all since the name is just the option name, which you can already know without this.If the submodule is defined under multiple
attrsOf
, thename
only tells you about the latest one. E.g.makes the
foo
option evaluate to{ bar = { baz = { name = "baz"; }; }; }
. You can see that the submodule doesn't get the information that it's under thebar
attribute.This changes fixes both of these problems by:
name
to the last relevant attribute the submodule is defined under, if any. For problem 1 this means that you now get an error that thename
argument isn't passed. Or if the submodule was defined in a deeper attribute set, it would return the attribute name of it, instead of the option name. This is backwards incompatible for submodules that relied on the option name it's defined under to change its behavior, but I think that's fine, because that isn't the intended use ofname
.names
argument, which contains them in reverse order. For problem 2 this means thatnames
gives you[ "baz" "bar" ]
. This is in reverse such that a static list index can be used to access elements, since the list can be arbitrarily long depending on where the submodule is evaluated.Ping @roberth
@rycee You'll be able to remove this workaround with this change: https://github.com/nix-community/home-manager/blob/249650a07ee2d949fa599f3177a8c234adbd1bee/modules/lib/types-dag.nix#L24-L28
Things done