Open lolbinarycat opened 8 months ago
relevant: #208242
the nix best practices page seems to imply that with
should basically never be used, this seems very extreme and would require rewriting basically every file in nixpkgs.
if we instead just recommend limiting its use to meta = with lib; { }
and maintainers = with maintainers; [ ]
, that would allow most unproblematic usages of with
to continue, while discouraging unusual and sometimes problematic usages.
i see a lot of
license = with licenses; [ mit ]
in PRs recently.
In my opinion, license should be a list, rather than "a list of licenses or a single license". The "singleton", even if being more typical, looks like an exception and not a rule.
So, as a personal preference, I am writing meta.license
as a list unconditionally.
maintainers is plural, which implies a list
License should be called licenses, precisely because there is at least one multiple-licensed project. But now it is too late to change that historical inconsistency...
seems to imply that with should basically never be used, this seems very extreme and would require rewriting basically every file in nixpkgs.
There is more: we didn't find a decent replacement for with
yet. The best we can do is to limit its use to predictable and easy-to-not-be-fooled examples.
To me, the exceptions are single-line statements, like:
Lists, with the restriction that the with
applies to each and every element:
with X; [ A B C D ];
# is shorter than
[ X.A X.B X.C X.D ];
# however, if X.C and X.D does not exist, use:
(with X; [ A B ]) ++ [ C D ];
# equivalent to
[ X.A X.B C D ];
the infamous toPythonApplication:
aocd = with python3Packages; toPythonApplication aocd;
# is shorter than
aocd = python3Packages.toPythonApplication python3Packages.aocd;
meta = with lib; { }
This was discouraged too.
This was discouraged too.
correction: this is no longer encouraged.
as best i am able to tell, the only person who has a major problem with meta = with lib;
is you. i am trying to document consensus, and one person's opinion does not consensus make.
i can drop meta = with lib
from "acceptable" to "discouraged" if you find someone to second your opinion, i suppose.
correction: this is no longer encouraged.
as best i am able to tell, the only person who has a major problem with
meta = with lib;
is you. i am trying to document consensus, and one person's opinion does not consensus make.
I made a similar point here: https://github.com/NixOS/nixpkgs/pull/292120#discussion_r1514555270
To put it bluntly, this needs to be discussed. We cannot force change through partial adoption of previously accepted views without discussion. As far as the previous PRs and issues I have seen, other committers have expressed objections. Relevant changes should not be merged until controversy is settled.
I've also yet to see a good reason why the 5 lines of the (usually trivial) meta
attribute are somehow too large of a scope to sensibly apply with
.
For entire package definitions or modules, that reason is easy to find as their code usually is not trivial where non-intuitive with;
bugs can creep up comparatively easily. (I've been bitten by a file-global with;
triggering infinite recursion a few weeks ago again.)
For rather small trivial scopes such as individual lists or a small attrset, this reason does not apply.
the 5 lines of the (usually trivial) meta attribute
Technically the current meta
recognizes 10 sub-attributes;
"It just works" is not a serious reason to make an exception to nested with;
The argument can be reversed: if the scope is so small, then there is no tactile gain in squeezing some bytes in it;
Further, it brings consistency to the use of with
, avoiding arguments of "small enough":
Being blunt, I have seen no reason for the guidelines above, besides "saving 10 characters per line"
find ./my-local-clone-of-nixpkgs
).@AndersonTorres trying to convince me is pointless, because it doesn't matter what i think. i'm trying to document consensus, not my own opinion.
(for the record, my only strong opinion is that with lib.maintainers
should be allowed)
You opened a PR associated with this issue (https://github.com/NixOS/nixpkgs/pull/294383) - and in ready-for-review status, rather than as a draft.
You even marked it as closing this issue. You are being inconsistent here.
It makes few to no sense to document consensus without polling opinions.
Many posts here - including those you are 👍-ing - express opinions and arguments, but only now that I am answering and arguing on them you suddenly remember you are merely documenting consensus?
You opened a PR associated with this issue (https://github.com/NixOS/nixpkgs/pull/294383) - and in ready-for-review status, rather than as a draft.
yes, because i want feedback on it (i.e. review)
It makes few to no sense to document consensus without polling opinions
correct! that's why i opened this issue before creating the PR! i also asked peoples' opinions in the matrix dev chatroom.
all of the actions i have taken i have done with the intent to get other people's opinions.
Many posts here - including those you are 👍-ing - express opinions and arguments, but only now that I am answering and arguing on them you suddenly remember you are merely documenting consensus?
i want to get several different perspectives on the issue.
they were a new voice, which is helpful
i am already well aware of your opinion, and you continuing to repeat it does nothing to establish consensus.
I've finally found a good example: version
can come from both lib
and the derivation itself.
This has now reared its head in an actual package (see https://github.com/NixOS/nixpkgs/pull/298316/files) where someone converted the mkDerivation
call to use the fixed-point parameter (mkDerivation (final: { ... })
), but missed changing one of the references to version
within meta
:
meta = with lib; {
changelog = "https://gitlab.archlinux.org/pacman/pacman/-/raw/v${version}/NEWS";
};
which in turn broke the changelog. No eval error, because version
easily came from lib
.
For another example where this would cause further issues, version
is an input for meta.platforms
in citrix-workspace
:
meta = with lib; {
platforms = [ "x86_64-linux" ] ++ optional (versionOlder version "24") "i686-linux";
};
In other words, were this converted to use the fixed-point parameter, and someone missed a spot to use said param, this would break meta.platforms
(!)
And to someone unaware of the scoping rules of with
, they may easily miss that version
is not meant to come from lib
, nor will the LSP or even nix itself warn them of this.
Perhaps it's time to put the footgun down and get rid of meta = with lib;
too.
Good catch!
And to someone unaware of the scoping rules of with, they may easily miss that version is not meant to come from lib, nor will the LSP or even nix itself warn them of this.
The rewritten nixd will probably be able to warn this!
I don't know if I am more impressed with such an awful example of unexpected with
, or with Pacman in Nixpkgs.
well, i stand corrected!
guess it's time to discourage with lib
in meta.
guess it's time to discourage
with lib
in meta.
I'm still on the fence with the removal of with lib
in meta. In the example which was given, couldn't you have version'
and lib.version
to explicitly state which ones? Or you could use let..in
and inherit (lib) ...
? Imo, the removal of with lib;
in meta and leaving everything to have the "long form" of pulling data does not look as clean as the with lib;
way.
I cannot get behind making packaging harder if the only potential benefit is it (sometimes) looks "cleaner".
As for using let
exprs, that still entails removing with
.
I cannot get behind making packaging harder if the only potential benefit is it (sometimes) looks "cleaner".
Understandable, though do we have to remove all with lib;
's when setting meta
? In the example you gave, there's two version variables. Not all packages will have duped variables. With the move to what #119942 implemented, maybe we could still use with lib;
as there would be finalAttrs.version
and so lib.version
wouldn't collide. With smaller or simpler packages, maybe we could still use with lib;
and if issues do arise then we could make the change?
does not look as clean as the
with lib;
way.
https://github.com/NixOS/rfcs/pull/110 is trying something to solve this
https://github.com/NixOS/rfcs/pull/110 is trying something to solve this
This certainly looks like a better and more proper alternative.
I've finally found a good example:
version
can come from bothlib
and the derivation itself.
Yes, with
can easily shadow other implicit bindings (as from rec
etc.)
I think it's still fine (and quite ergonomic) to use with
... outside of implicitly recursive attrsets, which have other issues anyways when it comes to derivations, like overrides not behaving as one could hope.
From that point of view, wouldn't it make more sense to deprecate the mkDerivation rec { ... }
antipattern instead?
not really an option yet since most of the builders don't support finalAttrs
. only mkDerivation
and the builders for nim and php do iirc
My suggestion is: just make sure the file is warning-free for escaping-with
(lsp diagnostics). That is, you can use with ...
in very deep level like with pkgs;
. But not use it as a top-level with lib;
because it may shadow things.
From that point of view, wouldn't it make more sense to deprecate the mkDerivation rec { ... } antipattern instead?
I like that idea! Nonetheless rec
has a long way to become really deprecated, and a truckload of people will never change to it except if the manual says it should.
https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+makeoverridable
I love the solution from Best Practices guide, but no one is ready for the elegance of self-reference yet :(
(lsp diagnostics)
Too dependent on tooling.
A "true" solution would be a new keyword.
Too dependent on tooling.
No. A styling guide may just suggest something neutral like: "don't make your variable look through with
env and bind to static names", to avoid https://github.com/NixOS/nix/issues/490 .
@inclyc could your escaping-with
check be ran stand-alone?
That'd be great to have for CI in Nixpkgs.
@inclyc could your
escaping-with
check be ran stand-alone?That'd be great to have for CI in Nixpkgs.
Yes.
https://github.com/nix-community/nixd/blob/main/libnixf/tools/nixf-tidy.cpp
nixf-tidy
, processes the file (stdin) and emit JSON diagnostics.
I have a draft action here: https://github.com/inclyc/nixf-tidy-action/blob/main/src/main.ts maybe someone would like to integrate it?
From that point of view, wouldn't it make more sense to deprecate the mkDerivation rec { ... } antipattern instead?
I like that idea! Nonetheless
rec
has a long way to become really deprecated [...]
Sure, and as @eclairevoyant pointed out, it's also dependent on (many) builders being updated. Thankfully, helpers have been submitted to make this much easier for builders' authors.
and a truckload of people will never change to it except if the manual says it should.
The same is true of trying to remove with lib;
etc.
I think that makes it all the more important that we focus on the most approriate idioms to uniformise everything on.
I love the solution from Best Practices guide, but no one is ready for the elegance of self-reference yet :(
If you mean naming the attrset to refer back to its contents, this does not solve the override issue either AFAIK.
(lsp diagnostics)
Too dependent on tooling.
Isn't this kind of thing what we have CI for?
A "true" solution would be a new keyword.
@AndersonTorres, could you clarify why you think a new keyword & corresponding language feature would be needed?
@inclyc
Too dependent on tooling.
No. A styling guide may just suggest something neutral like: "don't make your variable look through
with
env and bind to static names", to avoid NixOS/nix#490 .
i'm not sure how you think with
scoping works, but named varaiables will always be given priority over those in with
:
$ nix-instantiate --eval --expr 'let a = "outer"; in with { a = "inner"; }; a'
Isn't this kind of thing what we have CI for?
This can be mildly acceptable for editorconfig
, but LSP? It is many orders of magnitude bigger.
Being clearer: it is acceptable to install editorconfig
locally, but LSP is more complicated. CI-side can possibly do more things - like building things on Darwin.
This is like a Rust novice struggling with the borrow checker, with the additional load of sending the code remotely to OfBorg.
could you clarify why you think a new keyword & corresponding language feature would be needed?
The drawbacks of with
surpasses its slim benefits of squeezing some bytes. A new language construct, let it be a keyword, an operator or whatever, is what be need.
Not a "let the CI do the checks" thing.
About this:
@inclyc
Too dependent on tooling.
No. A styling guide may just suggest something neutral like: "don't make your variable look through
with
env and bind to static names", to avoid NixOS/nix#490 .i'm not sure how you think
with
scoping works, but named varaiables will always be given priority over those inwith
:$ nix-instantiate --eval --expr 'let a = "outer"; in with { a = "inner"; }; a'
Yes. If you read the links to NixOS/nix issue, this scoping rule is in-fact a thing we are trying to avoid.
Link: https://github.com/NixOS/nix/issues/490 Link: https://github.com/NixOS/nix/pull/10620
This can be mildly acceptable for editorconfig, but LSP? It is many orders of magnitude bigger.
If you read the comments above, you will know lsp diagnostics' could be run as a standalone tooling. A single exe with even smaller closure size than nix-instantiate
.
The drawbacks of with surpasses its slim benefits of squeezing some bytes. A new language construct, let it be a keyword, an operator or whatever, is what be need.
For now we cannot "remove" or even "deprecate" any language constructs by introducing a new one. Thus I think "introducing a new keyword or somehow" cannot resolve "overuse of with
".
Think about it: if there are actually some RFCs accepted, then we must :
with
how can we achieve this?
Since we cannot "remove" something from a language, there are merely two approaches to keep the code clean:
Not a "let the CI do the checks" thing.
IMHO nixpkgs maintainers have more important things to do, e.g.
So why not offload the "syntax checking" burden to automated tools?
After a month looking at the pile of notifications, I have read this only now.
It seems the check added in #330066 will get us closer to cleaning up meta = with lib;
:tada:
Unfortunately that specific error reporting is turned off again for now, see https://github.com/NixOS/nixpkgs/pull/330454 :sweat_smile:
Problem
i see a lot of
license = with licenses; [ mit ]
in PRs recently.compared to the simpler
license = licenses.mit
, this is both longer and more syntactically complex, taking longer to read for humans, and possibly longer to evaluate too.Proposal
this should be avoided for single-license packages (which is most of them).
this would not apply to
meta.maintainers
, for the following reason:maintainers
is plural, which implies a listi would be willing to write this into
pkgs/README.md
but i'm not going to open a PR until i've gotten some feedback, it wouldn't make sense for me to single-handedly decide what the best practice is.Add a :+1: reaction to issues you find important.