Nix Language Quirks: Difference between revisions
imported>Danbst added function argument destructuring |
imported>Danbst added imports and namespacing section |
||
| Line 55: | Line 55: | ||
These <code>x</code> and <code>y</code> are in fact <code>let</code>-bindings, but overridable ones. | These <code>x</code> and <code>y</code> are in fact <code>let</code>-bindings, but overridable ones. | ||
== Imports and namespaces == | |||
There is a keyword <code>import</code>, but it's equivalent in other languages is <code>eval</code>. It can be used for namespacing too: | |||
<nowiki>let | |||
pkgs = import <nixpkgs> {}; | |||
lib = import <nixpkgs/lib>; | |||
in | |||
pkgs.runCommand (lib.strings.removePrefix "....</nowiki> | |||
consider using <code>import</code> here as using <code>qualified import ...</code> in Haskell or <code>import ...</code> in Python. | |||
Another way of importing is <code>with import ...;</code>, which corresponds to Python <code>from ... import *</code>. | |||
But because of not very great IDE support in Nix, <code>with import ...;</code> is discouraged. Rather use <code>inherit</code>, especially if you are targeting source code for Nix newcomers: | |||
<nowiki> | |||
let | |||
lib = import <nixpkgs/lib>; | |||
inherit (lib.strings) | |||
removePrefix removeSuffix | |||
; | |||
inherit (lib.lists) | |||
isList init drop | |||
; | |||
in | |||
removePrefix ...</nowiki> | |||
<code>inherit</code> has higher priority than <code>with</code>, and conflicts with <code>let</code> | |||
<nowiki> | |||
nix-repl> let pkgs = { x = 1; }; x = 2; x = 3; inherit (pkgs) x; in x | |||
error: attribute ‘x’ at (string):1:31 already defined at (string):1:24</nowiki> | |||
This makes it a sane citizen of Nix lanugage... except it has a twin, called <code>{ inherit ...; }</code>. They DON'T do the same - <code>let inherit ...</code> adds let-bindings, and <code>{ inherit ...; }</code> adds attributes to a record. | |||
Revision as of 11:11, 26 October 2017
with and let
with gets less priority then let. This can lead to confusions, especially if you like to write with pkgs;:
nix-repl> pkgs = { x = 1; }
nix-repl> with pkgs; x
1
nix-repl> with pkgs; let x = 2; in x
2
So we see, that let binding overrides with binding. But what about this?
nix-repl> let x = 2; in with pkgs; x 2
Nah, with and let have different priority when resolving names.
Old let syntax
This is an old Nix syntax, that probably isn't used much
nix-repl> let { x = 1; y = x + 1; body = y; }
2
It is equivalent to modern syntax expression let x = 1; y = x + 1; in y. Note, that it doesn't require rec keyword.
Note, that it isn't equivalent to with rec { x = 1; y = x + 1; body = y; }; body because of mentioned with and let quirk, but is same as rec { x = 1; y = x + 1; body = y; }.body
Something that looks like both record attribute and let-binding
Destructuring function argument - is a great feature of Nix.
nix-repl> f = { x ? 1, y ? 2 }: x + y
nix-repl> f { }
3
The fact that we can add @args argument assignment is also cool
nix-repl> f = { x ? 1, y ? 2, ... }@args: with args; x + y + z
nix-repl> f { z = 3; }
6
But don't be fooled, args doesn't necessarily contain x and y:
nix-repl> f = { x ? 1, y ? 2, ... }@args: args.x + args.y + args.z
nix-repl> f { z = 3;}
error: attribute ‘x’ missing, at (string):1:30
These x and y are in fact let-bindings, but overridable ones.
Imports and namespaces
There is a keyword import, but it's equivalent in other languages is eval. It can be used for namespacing too:
let
pkgs = import <nixpkgs> {};
lib = import <nixpkgs/lib>;
in
pkgs.runCommand (lib.strings.removePrefix "....
consider using import here as using qualified import ... in Haskell or import ... in Python.
Another way of importing is with import ...;, which corresponds to Python from ... import *.
But because of not very great IDE support in Nix, with import ...; is discouraged. Rather use inherit, especially if you are targeting source code for Nix newcomers:
let
lib = import <nixpkgs/lib>;
inherit (lib.strings)
removePrefix removeSuffix
;
inherit (lib.lists)
isList init drop
;
in
removePrefix ...
inherit has higher priority than with, and conflicts with let
nix-repl> let pkgs = { x = 1; }; x = 2; x = 3; inherit (pkgs) x; in x
error: attribute ‘x’ at (string):1:31 already defined at (string):1:24
This makes it a sane citizen of Nix lanugage... except it has a twin, called { inherit ...; }. They DON'T do the same - let inherit ... adds let-bindings, and { inherit ...; } adds attributes to a record.