Nix Language Quirks: Difference between revisions
Change the title of the ${null} attribute set entry since delete is misleading. Also link to the official documentation about it |
m propose merge |
||
| (15 intermediate revisions by one other user not shown) | |||
| Line 1: | Line 1: | ||
{{merge|Nix | {{merge|Nix (language)}} | ||
== <code>with</code> and <code>let</code> == | == <code>with</code> and <code>let</code> == | ||
| Line 20: | Line 20: | ||
2 </syntaxHighlight> | 2 </syntaxHighlight> | ||
In this case, <code>with</code> and <code>let</code> have different priority when resolving names. | |||
[https://github.com/NixOS/nix/issues/1361 Good discussion on this topic] | [https://github.com/NixOS/nix/issues/1361 Good discussion on this topic] | ||
Generally the use of <code>with</code> is discouraged. See the [https://nix.dev/guides/best-practices#with-scopes best practices guide] for how best to use <code>inherit</code> as an alternative. | |||
== Old <code>let</code> syntax == | == Old <code>let</code> syntax == | ||
This is an old Nix syntax, that probably isn't used much | This is an [https://github.com/NixOS/nix/issues/1361#issuecomment-323050690 old] Nix syntax, that probably isn't used much | ||
<syntaxHighlight lang=nix> | <syntaxHighlight lang=nix> | ||
nix-repl> let { x = 1; y = x + 1; body = y; } | nix-repl> let { x = 1; y = x + 1; body = y; } | ||
| Line 34: | Line 36: | ||
Note, that it isn't equivalent to <code>with rec { x = 1; y = x + 1; body = y; }; body</code> because of mentioned <code>with</code> and <code>let</code> quirk, but is same as <code>rec { x = 1; y = x + 1; body = y; }.body</code> | Note, that it isn't equivalent to <code>with rec { x = 1; y = x + 1; body = y; }; body</code> because of mentioned <code>with</code> and <code>let</code> quirk, but is same as <code>rec { x = 1; y = x + 1; body = y; }.body</code> | ||
== Default values are not bound in @ syntax == | == Default values are not bound in <code>@</code> syntax == | ||
Destructured arguments can have default values, but those default values are part of the full function argument. | Destructured arguments can have default values, but those default values are part of the full function argument. | ||
| Line 73: | Line 75: | ||
== Imports and namespaces == | == Imports and namespaces == | ||
Nix includes a keyword <code>import</code>, but it's equivalent in other languages is <code>eval</code>. | |||
It is typically be used for namespacing: | |||
<syntaxHighlight lang=nix>let | <syntaxHighlight lang=nix>let | ||
| Line 81: | Line 85: | ||
pkgs.runCommand (lib.strings.removePrefix ".... </syntaxHighlight> | pkgs.runCommand (lib.strings.removePrefix ".... </syntaxHighlight> | ||
consider | consider the use of <code>import</code> here similar to using <code>qualified import ...</code> in Haskell or <code>import ...</code> in Python. Another (discouraged and increasingly uncommon) way of importing is [https://nix.dev/manual/nix/2.24/language/syntax#with-expressions <code>with import ...;</code>], which corresponds to Python <code>from ... import *</code>. This use of <code>with</code> imports everything from the target into scope, which has numerous potential gotchas and problems, and so using [https://nix.dev/guides/best-practices#with-scopes <code>inherit</code>] instead is encouraged and preferred. | ||
Another way of importing is <code>with import ...;</code>, which corresponds to Python <code>from ... import *</code>. | |||
== <code>builtins.replaceStrings</code> key match on "" == | |||
Syntax: | Syntax: | ||
| Line 113: | Line 94: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
The [https://noogle.dev/f/builtins/replaceStrings <code>builtins.replaceStrings</code>] function allows matching <code>""</code> in <code>string</code>. <code>[match]</code> gets checked sequentially, and when <code>""</code> is checked - it ''always'' matches. And so - when <code>""</code> is checked it ''always'' inserts the corresponding replacement from <code>[replace]</code>, then the next char in <code>string</code> gets inserted, and then the next char after that from <code>string</code> gets processed. | |||
<syntaxHighlight lang=nix> | <syntaxHighlight lang=nix> | ||
nix-repl> builtins.replaceStrings ["" "e"] [" " "i"] "Hello world" | nix-repl> builtins.replaceStrings ["" "e"] [" " "i"] "Hello world" | ||
| Line 121: | Line 102: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
== Indented | == Indented strings trim leading whitespace == | ||
Leading spaces are removed from both single-line and multi-line <strong>indented strings</strong>. | |||
Leading spaces are removed | |||
<syntaxHighlight lang=nix> | <syntaxHighlight lang=nix> | ||
| Line 131: | Line 110: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
Usually, | Usually, indented strings have multiple lines: | ||
<syntaxHighlight lang=nix> | <syntaxHighlight lang=nix> | ||
| Line 147: | Line 126: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
This is documented in more detail in the [https://nix.dev/manual/nix/2.24/language/syntax#string-literal String section] of the Nix reference manual. Also see [https://github.com/NixOS/nix/issues/7834 NixOS/nix#7834] and [https://github.com/NixOS/nix/pull/9971 NixOS/nix#9971] for more information. | |||
== Integer precision == | == Integer precision == | ||
Integer precision is limited to 64 | Integer precision is limited to [https://en.m.wikipedia.org/wiki/64-bit_computing 64-bit] in the original Nix interpreter. | ||
So the valid integer range is from -2**63 to 2**63-1 = from -9223372036854775808 to 9223372036854775807 | So the valid integer range is from -2**63 to 2**63-1 = from -9223372036854775808 to 9223372036854775807 | ||
| Line 217: | Line 196: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
This might used as an alternative to conditionally merging attribute sets using <code>//</code> like the following: | This might be used as an alternative to conditionally merging attribute sets using <code>//</code> like the following: | ||
<syntaxHighlight lang=nix> | <syntaxHighlight lang=nix> | ||
{ a = "b"; } // (if true then { foo = "bar"; } else { } ) | { a = "b"; } // (if true then { foo = "bar"; } else { } ) | ||
</syntaxHighlight> | |||
== Hexadecimal, octal, and binary == | |||
As of late 2024, Nix doesn't contain builtin support for parsing many number formats like hexadecimal, octal, and binary. It ''does'', however, support the [https://noogle.dev/f/builtins/fromTOML <code>builtins.fromTOML</code>] function, which [https://github.com/NixOS/nix/issues/7578#issuecomment-1955985859 can be used] to parse these number formats. | |||
<syntaxHighlight lang=nix> | |||
nix-repl> (builtins.fromTOML "octal = 0o11").octal | |||
9 | |||
nix-repl> (builtins.fromTOML "binary = 0b1001").binary | |||
9 | |||
nix-repl> (builtins.fromTOML "hex = 0x09").hex | |||
9 | |||
</syntaxHighlight> | |||
== Mimicking case statements with attribute sets == | |||
Nix doesn't include native support for case statements, however when dealing with string types it's possible to use some string interpolation behavior to achieve something similar to case statement behavior, as described in this [https://discourse.nixos.org/t/case-statement-expr/27741/12 thread]. | |||
In the example from the thread, given some string argument <code>x</code>, the following code would place different values into a text file depending on it's value: | |||
<syntaxHighlight lang=nix> | |||
environment.etc."just/for/test".text = { | |||
"a" = "hello"; | |||
"b" = "hi"; | |||
"c" = "ciao"; | |||
}."${x}"; | |||
</syntaxHighlight> | |||
So if <code>x</code> is set to the string <code>"a"</code> then the <code>just/for/test</code> file contents would be set to the string <code>"hello"</code>. The code above is the same in behavior to the following, more common, if-else-style construct: | |||
<syntaxHighlight lang=nix> | |||
environment.etc."just/for/test".text = | |||
if x == "a" then | |||
"hello" | |||
else if x == "b" then | |||
"hi" | |||
else if x == "c" then | |||
"ciao" | |||
else | |||
abort "x is invalid"; | |||
</syntaxHighlight> | |||
There is an example in <code>coq</code> package code [https://github.com/NixOS/nixpkgs/blob/5185539c51ba658e70b29e01c0c320a85f4e2098/pkgs/build-support/coq/extra-lib.nix#L98 here] where someone used this behavior to build a reusable function <code>switch</code>. | |||
== <code>builtins.toString</code> handling of <code>true</code> and <code>false</code> is inconsistent == | |||
<syntaxHighlight lang=nix> | |||
nix-repl> builtins.toString true | |||
"1" | |||
nix-repl> builtins.toString false | |||
"" | |||
</syntaxHighlight> | </syntaxHighlight> | ||
| Line 256: | Line 290: | ||
nix-repl> let code = "(x: x) ''id function was called''"; in import (builtins.toFile "eval" code) | nix-repl> let code = "(x: x) ''id function was called''"; in import (builtins.toFile "eval" code) | ||
"id function was called"</syntaxHighlight> | "id function was called"</syntaxHighlight> | ||
= Resources = | |||
* [https://md.darmstadt.ccc.de/xtNP7JuIQ5iNW1FjuhUccw# A separately maintained list of Nix language quirks] | |||
[[Category:Nix Language]] | [[Category:Nix Language]] | ||