5 ms·
I agree the syntax isn't perfect, but in case you're actually confused there's really only 3 places where semicolons go, and I would argue that two of the place
by 418tpot 1y ago
I agree the syntax isn't perfect, but in case you're actually confused there's really only 3 places where semicolons go, and I would argue that two of the places make a lot of sense— as a terminator for attribute sets, and a terminator for `let` declarations.
Unfortunately it is also used with the somewhat confusing `with` operator which I personally avoid using. For those of you who aren't familiar, it works similar to the now deprecated javascript `with` statement where `with foo; bar` will resolve to `bar` if it is in scope, otherwise it will resolve to `foo.bar`.
- pkulak 1y agoYour p,k,g,s keys must be worn to nubs.
- wiktor-k 1y ago> now deprecated javascript `with` statement where `with foo; bar` will resolve to `bar` if it is in scope, otherwise it will resolve to `foo.bar`. Technically, in JavaScript it's `with (foo) bar`. Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- chriswarbo 1y agoI 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 1y 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 1y 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; }