Nix Language Quirks: Difference between revisions

Indented strings trim leading whitespace: Remove unnecessary sentence and clarify wording
Tags: Mobile edit Mobile web edit
DoggoBit (talk | contribs)
m propose merge
 
(7 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{merge|Nix Expression Language|same type of information in the expression language article}}
{{merge|Nix (language)}}


== <code>with</code> and <code>let</code> ==
== <code>with</code> and <code>let</code> ==
Line 36: 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 75: Line 75:


== Imports and namespaces ==
== 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:
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 83: Line 85:
   pkgs.runCommand (lib.strings.removePrefix ".... </syntaxHighlight>
   pkgs.runCommand (lib.strings.removePrefix ".... </syntaxHighlight>


consider using <code>import</code> here as using <code>qualified import ...</code> in Haskell or <code>import ...</code> in Python.  
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>.
 
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:
 
  <syntaxHighlight lang=nix>
let
  lib = import <nixpkgs/lib>;
  inherit (lib.strings)
    removePrefix removeSuffix
  ;
  inherit (lib.lists)
    isList init drop
  ;
in
  removePrefix ... </syntaxHighlight>
 
<code>inherit</code> has higher priority than <code>with</code>, and conflicts with <code>let</code>
 
  <syntaxHighlight lang=nix>
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 </syntaxHighlight>
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.


== builtins.replaceStrings key match on "" ==
== <code>builtins.replaceStrings</code> key match on "" ==


Syntax:
Syntax:
Line 221: Line 200:
<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]]