3 ms·
I actually prefer `with`, since it fits better with the language: - It uses `;` in the same way as `assert`, whereas `let` uses a whole other keyword `in`. -
by chriswarbo 2y ago
I actually prefer `with`, since it fits better with the language:
- It uses `;` in the same way as `assert`, whereas `let` uses a whole other keyword `in`.
- It uses attrsets as reified/first-class environments, unlike `let`, which lets us do `with foo; ...`.
- Since it uses attrsets, we can use their existing functionality, like `rec` and `inherit`; rather than duplicating it.
I've been using Nix for over a decade (it's even on my phone), and I've never once written a `let`.
(I agree that the shadowing behaviour is annoying, and we're stuck with it for back-compat; but that's only an issue for function arguments and let, and I don't use the latter)
- 418tpot 2y agoInteresting, are you saying that instead of reaching for `let foo = bar; in expr` you usually use something like `with { foo = bar; }; expr`? > Since it uses attrsets, we can use their existing functionality, like `rec` and `inherit`; rather than duplicating it. `let` supports `inherit`, and is always `rec`. Or is that your point, that it is needlessly duplicated functionality?
- chriswarbo 2y agoYes and yes :) Functions with default arguments are also very useful; especially since `nix-build` will call them automatically. Those are "always `rec`" too, which (a) makes them convenient for intermediate values, and (b) provides a fine-grained way to override some functionality. I used this to great effect at a previous employer, for wrangling a bunch of inter-dependent Maven projects; but here's a made-up example: { # Main project directory. Override to build a different version. src ? pkgs.lib.cleanSource ./. # Take these files from src by default, but allow them to be overridden , config ? "${src}/config.json" , script ? "${src}/script.sh" # A couple of dependencies , jq ? pkgs.jq , pythonEnv ? python3.withPackages choosePyPackages , extraDeps ? [] # Not necessary, but might be useful for callers # Python is tricky, since it bakes all of its libraries into one derivation. # Exposing intermediate parts lets us override just the interpreter, or just # the set of packages, or both. , python3 ? pkgs.python3 , choosePyPackages ? (p: pythonDeps p ++ extraPythonDeps p) , pythonDeps ? (p: [ p.numpy ]) , extraPythonDeps ? (p: []) # Again, not necessary but maybe useful # Most of our dependencies will ultimately come from Nixpkgs, so we should pin # a known-good revision. However, we should also allow that to be overridden; # e.g. if we want to pass the same revision into a bunch of projects, for # consistency. , pkgs ? import ./pinned-nixpkgs.nix }: # Some arbitrary result pkgs.writeShellApplication { name = "foo"; runtimeInputs = [ jq pythonEnv ] ++ extraDeps; runtimeEnv = { inherit config; }; text = builtins.readFile script; }