nix.dev icon indicating copy to clipboard operation
nix.dev copied to clipboard

Advice regarding alternatives to the `with attrset;` antipattern doesn't apply in general.

Open nothingnesses opened this issue 4 years ago • 7 comments

The advice in this section doesn't apply if the list elements are nested attribute sets (i.e., they have dots) or are function applications (i.e., they are surrounded by parentheses). Maybe other alternatives in these cases should also be provided?

nothingnesses avatar Oct 04 '21 14:10 nothingnesses

pkgs in the example is a nested attribute set, so I'm not sure what do you mean.

Can you provide an example?

domenkozar avatar Oct 04 '21 15:10 domenkozar

Sure thing. So here's a part of the "home.nix" configuration I use for Home Manager, which builds fine:

{ config, pkgs, ... }:
let
	inherit (builtins)
	fetchGit;
in
{
	home = {
		homeDirectory = "/home/a";
		packages = with pkgs; [
			(nix_gl alacritty)
			rust-bin.stable.latest.default
		];
		stateVersion = "21.11";
		username = "a";
	};
	nixpkgs = {
		overlays = [
			(self: super: {
				nix_gl_go = (import (fetchGit {
					ref = "main";
					url = "https://github.com/guibou/nixGL.git";
				}) {}).nixGLIntel;
				nix_gl = program: pkgs.writeShellScriptBin program.pname ''
					${self.nix_gl_go}/bin/nixGLIntel ${program}/bin/${program.pname} "$@"
				'';
			})
			(import (fetchGit {
				ref = "master";
				url = "https://github.com/oxalica/rust-overlay.git";
			}))
		];
	};
	targets.genericLinux.enable = true;
}

But it doesn't work if I try to apply the pattern from the website:

{ config, pkgs, ... }:
let
	inherit (builtins)
	attrValues
	fetchGit;
in
{
	home = {
		homeDirectory = "/home/a";
		packages = attrValues {
			inherit (pkgs)
			(nix_gl alacritty)
			rust-bin.stable.latest.default;
		};
		stateVersion = "21.11";
		username = "a";
	};
	nixpkgs = {
		overlays = [
			(self: super: {
				nix_gl_go = (import (fetchGit {
					ref = "main";
					url = "https://github.com/guibou/nixGL.git";
				}) {}).nixGLIntel;
				nix_gl = program: pkgs.writeShellScriptBin program.pname ''
					${self.nix_gl_go}/bin/nixGLIntel ${program}/bin/${program.pname} "$@"
				'';
			})
			(import (fetchGit {
				ref = "master";
				url = "https://github.com/oxalica/rust-overlay.git";
			}))
		];
	};
	targets.genericLinux.enable = true;
}

Hopefully that shows what I mean clearly. That said, I'm pretty new to Nix, so it's just as likely that I'm not doing things properly. In that case, please do let me know the proper way so I can improve.

nothingnesses avatar Oct 04 '21 16:10 nothingnesses

Thanks!

Indeed for referencing nested attributes the example doesn't work. Same for functions!

In that case it's best to refer to pkgs.rust-bin and pkgs.nix_gl.

domenkozar avatar Oct 04 '21 16:10 domenkozar

What if the section included advice about using the concatLists builtin to allow the problematic attribute sets to be included using the longhand form, whilst still allowing the original advice about the shorthand form to be used when applicable? So the result will be something like:

{ config, pkgs, ... }:
let
	inherit (builtins)
	attrValues
	concatLists
	fetchGit;
in
{
	home = {
		homeDirectory = "/home/a";
		packages = concatLists [
			(attrValues {
				inherit (pkgs)
				bc
				gcc
				gdb
				ripgrep;
			})
			[
				(pkgs.nix_gl pkgs.alacritty)
				pkgs.rust-bin.stable.latest.default
			]
		];
		stateVersion = "21.11";
		username = "a";
	};
	nixpkgs = {
		overlays = [
			(self: super: {
				nix_gl_go = (import (fetchGit {
					ref = "main";
					url = "https://github.com/guibou/nixGL.git";
				}) {}).nixGLIntel;
				nix_gl = program: pkgs.writeShellScriptBin program.pname ''
					${self.nix_gl_go}/bin/nixGLIntel ${program}/bin/${program.pname} "$@"
				'';
			})
			(import (fetchGit {
				ref = "master";
				url = "https://github.com/oxalica/rust-overlay.git";
			}))
		];
	};
	targets.genericLinux.enable = true;
}

I'm not sure if there's a more concise way to do this than using concatLists, and if so, maybe that could be used instead?

nothingnesses avatar Oct 05 '21 12:10 nothingnesses

I wonder if the complexity of reading the code of figuring out concatLists and attrValues is really worth typing out pkgs 3 times more than it is currently?

domenkozar avatar Oct 05 '21 16:10 domenkozar

The value of doing this would likely depend on how many elements the list has. I only included a few in the example above but my actual configuration has more than a dozen elements, so in my case I think it is justified, but in cases of small lists, this wouldn't be worth doing. In any case, I think it's still worth including this advice (or any other similar, simpler solution, if it exists) because the current advice in the website doesn't apply to all cases as mentioned previously. Readers can just decide for themselves if they think it's worth doing depending on their situation (i.e., they might decide to use it if their lists are large enough).

nothingnesses avatar Oct 05 '21 17:10 nothingnesses

Thanks to @r-burns we now have a language proposal to make this simpler: https://github.com/NixOS/rfcs/pull/110

domenkozar avatar Oct 19 '21 21:10 domenkozar