1
Fork 0
mirror of https://github.com/RGBCube/Site synced 2025-08-01 13:37:49 +00:00

nix-iceberg: more text

This commit is contained in:
RGBCube 2025-06-05 03:13:51 +03:00
parent 8dade43fbd
commit 48a2e697c4
Signed by: RGBCube
SSH key fingerprint: SHA256:CzqbPcfwt+GxFYNnFVCqoN5Itn4YFrshg1TrnACpA5M
3 changed files with 200 additions and 128 deletions

14
site.ts
View file

@ -154,12 +154,12 @@ site.use(sitemap({
site.use(lightningcss()); // TODO: LightningCSS doesn't handle inline styles. site.use(lightningcss()); // TODO: LightningCSS doesn't handle inline styles.
site.use(inline()); site.use(inline());
site.use(minifyHtml({ // site.use(minifyHtml({
options: { // options: {
// TODO: This breaks tailwind. // // TODO: This breaks tailwind.
// minify_css: true, // // minify_css: true,
minify_js: true, // minify_js: true,
}, // },
})); // }));
export default site; export default site;

View file

@ -180,7 +180,7 @@ html, body {
} }
&:not(:has(h1, h2, h3, h4, h5, h6)) { &:not(:has(h1, h2, h3, h4, h5, h6)) {
@apply inline-block wrap-anywhere text-[red] dark:text-[yellow] border-2 @apply inline wrap-anywhere text-[red] dark:text-[yellow] border-2
border-[transparent] border-dashed; border-[transparent] border-dashed;
&:has(> code:only-child) { &:has(> code:only-child) {

View file

@ -9,24 +9,28 @@ keywords:
- nix - nix
--- ---
I was surfing the web a few weeks ago, and I came across this iceberg chart: Everyone who has ever interacted with Nix tooling knows that it keeps some
secrets. It even keeps some so well hidden that it hinders its adoption, giving
it a reputation of being arcane and hard to use.
I'll be explaining the contents of the following iceberg chart, which includes
some truly arcane examples of Nix code.
Some knowledge of Nix is required, you may get confused in the terminology if
you've never used it.
![The Nix Iceberg](/assets/images/nix-iceberg.webp) ![The Nix Iceberg](/assets/images/nix-iceberg.webp)
[Here's the original source for this image, [Here's the original source for this image, on cohost.](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg)
created by @leftpaddotpy, @puckipedia,
@wiggles and @qyriad on cohost.](https://cohost.org/leftpaddotpy/post/3885451-the-nix-iceberg)
In this post, I'll be explaining every item in this iceberg with sufficient Let's start:
depth. Let's start:
# Tier 1: I use NixOS (BTW) # Tier 1: `btw I use NixOS`
## IFD blocks evaulation ## IFD blocks evaulation
> IFD stands for import-from-derivation. IFD (**I**mport-**F**rom-**D**erivation) is when you import a Nix expression
from a derivation in the Nix store.
IFD is when you import a Nix expression from a derivation in the Nix store.
For example: For example:
@ -38,8 +42,8 @@ let
echo '{ a = "b"; }' > $out echo '{ a = "b"; }' > $out
''; '';
mySet = import myNixExprDeriv; myAttributes = import myNixExprDeriv;
in mySet.a in myAttributes.a
``` ```
This will evaluate to `"b"`. This will evaluate to `"b"`.
@ -49,13 +53,13 @@ So, what are we doing in this snippet?
1. Importing `<nixpkgs>` and getting the packages out of it. 1. Importing `<nixpkgs>` and getting the packages out of it.
2. Creating a derivation that runs an echo command, which writes a Nix 2. Creating a derivation that runs an echo command, which writes a Nix
expression to the output file. expression to the output file.
3. Then we import the expression, forcing the derivation to be realized as we 3. Then we import the output file, forcing the derivation to be realized as we
accessed the contents of it. accessed the contents of it.
> Wait, what does _realization_ mean? > Wait, what does _realization_ mean?
It means to actually build a `.drv` file, using the builder, arguments and It means to actually build a derivation, using the builder, arguments and inputs
inputs described in it. described within.
Nix does not realize derivations until you access the contents of them or force Nix does not realize derivations until you access the contents of them or force
them to be evaluated using the `:b` command in the Nix REPL, see these two them to be evaluated using the `:b` command in the Nix REPL, see these two
@ -68,9 +72,9 @@ nix-repl> pkgs.runCommand "foo" {} "echo 'bar' > $out"
«derivation /nix/store/h27fzbivcxw0cc1bxyyyqyivpw9rsz6k-foo.drv» «derivation /nix/store/h27fzbivcxw0cc1bxyyyqyivpw9rsz6k-foo.drv»
``` ```
Here, it did create a `.drv` file. But that's it. There is no Here, it created a `.drv` file, which is how derivations are represented. But
`/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-foo` with contents `bar` to be that's it. There is no `/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-foo` with
seen. contents `bar` to be seen.
```nix ```nix
nix-repl> :b pkgs.runCommand "foo" {} "echo 'bar' > $out" nix-repl> :b pkgs.runCommand "foo" {} "echo 'bar' > $out"
@ -86,15 +90,15 @@ Where were we again? Right, the 3rd point:
be realized as we accessed the contents of it.` be realized as we accessed the contents of it.`
The 3rd point is the important part. A typical Nix expression does not depend on The 3rd point is the important part. A typical Nix expression does not depend on
the output contents of any derivation, which in turn makes evaluating a Nix the output of any derivation, which in turn makes evaluating a Nix expression
expression not require realizing _any_ derivations. not require realizing _any_ derivations whatsoever.
But with IFD, you have to realize a derivation to even finish the evaluation of But with IFD, you have to realize a derivation to even finish the evaluation of
your Nix expression. This will block Nix evaluation for a long time, as Nix is your Nix expression. This will block Nix evaluation for a long time, as Nix is
evaluated on a single thread and realizing the derivation needed takes a evaluated on a single thread and realizing any derivation takes a non-trivial
non-trivial amount of time. amount of time.
TL;DR: IFD blocks evaluation because: ### TL;DR: IFD blocks evaluation because:
1. Evaluation is single threaded, so naturally everything blocks it. 1. Evaluation is single threaded, so naturally everything blocks it.
2. You're trying to access a derivation _output_, so obviously you need to 2. You're trying to access a derivation _output_, so obviously you need to
@ -111,45 +115,43 @@ the `--packages/-p` argument for `nix-shell`
`nix-shell -p` is similar to `nix shell`. But they are not the same. `nix-shell -p` is similar to `nix shell`. But they are not the same.
`nix-shell -p` creates a shell using the stdenv by calling `pkgs.mkShell`, which `nix-shell -p` creates a shell using the nixpkgs stdenv (and thus depends on
includes all packages in the nixpkgs stdenv plus the ones you specified. nixpkgs) by calling `pkgs.mkShell`, which includes all packages in the nixpkgs
stdenv plus the ones you specified.
`nix shell` only appends the packages you passed in to the `PATH` environment `nix shell` only appends the packages you passed in to the `PATH` environment
variable. It is much lighter, as a natural result of not using the stdenv. It variable. It is much lighter, as a natural result of not using nixpkgs or its
also isn't a questionable templated Nix expression and is implemented in the Nix stdenv. It also doesn't have as much of a questionable implementation, as it is
CLI natively. in C++ and in Nix natively instead of being a Perl script that uses string
interpolation to produce Nix expressions.
## Hydra is 17,000 lines of Perl ## hydra is 17 000 lines of perl
As the title says, [Hydra](http://github.com/NixOS/hydra), the Nix-based [Hydra](http://github.com/NixOS/hydra), the Nix-based continuous build system is
continuous build system is almost 17,000 lines of Perl. almost 17,000 lines of Perl.
Here is the `tokei` output for its GitHub repository: Here is the `tokei` output for its GitHub repository:
| Language | Files | Lines | Code | Comments | Blanks | | Language | Files | Lines | Code | Comments | Blanks |
| ---------------- | ----- | ----------- | ----- | -------- | ------ | | ---------- | ----- | ------------------------------------------- | ----- | -------- | ------ |
| Autoconf | 2 | 38 | 37 | 0 | 1 | | Autoconf | 2 | 38 | 37 | 0 | 1 |
| Automake | 13 | 175 | 150 | 0 | 25 | | C++ | 8 | 4140 | 3068 | 360 | 712 |
| C++ | 9 | 4659 | 3448 | 406 | 805 | | C++ Header | 5 | 768 | 492 | 75 | 201 |
| C++ Header | 5 | 757 | 485 | 74 | 198 | | CSS | 3 | 505 | 388 | 35 | 82 |
| CSS | 3 | 505 | 388 | 35 | 82 | | JavaScript | 6 | 343 | 270 | 37 | 36 |
| JavaScript | 6 | 337 | 265 | 37 | 35 | | JSON | 1 | 24 | 24 | 0 | 0 |
| Nix | 38 | 2029 | 1732 | 77 | 220 | | Meson | 10 | 328 | 293 | 9 | 26 |
| Nix (Markdown) | 2 | 12 | 12 | 0 | 0 | | Nix | 48 | 2266 | 1948 | 84 | 234 |
| Perl | 125 | 16754 (!!!) | 12055 | 649 | 4050 | | Perl | 127 | [**17023**](#hydra-is-17-000-lines-of-perl) | 12258 | 663 | 4102 |
| Python | 1 | 35 | 25 | 1 | 9 | | Python | 1 | 35 | 25 | 1 | 9 |
| Shell | 24 | 371 | 279 | 35 | 57 | | Shell | 24 | 371 | 279 | 35 | 57 |
| Shell (Markdown) | 1 | 3 | 2 | 1 | 0 | | SQL | 85 | 1406 | 989 | 202 | 215 |
| SQL | 85 | 1406 | 989 | 202 | 215 | | SVG | 6 | 6 | 6 | 0 | 0 |
| SVG | 6 | 6 | 6 | 0 | 0 | | Plain Text | 4 | 164 | 0 | 102 | 62 |
| Plain Text | 4 | 164 | 0 | 102 | 62 | | YAML | 1 | 1137 | 1094 | 0 | 43 |
| YAML | 1 | 1137 | 1094 | 0 | 43 | | Total | 349 | 30927 | 21210 | 3358 | 6359 |
| XML (Markdown) | 2 | 25 | 25 | 0 | 0 |
| Markdown | 18 | 2312 | 0 | 1744 | 568 |
| Markdown (Total) | 18 | 2352 | 39 | 1745 | 568 |
| Total | 340 | 30685 | 20953 | 3362 | 6370 |
## Nix Pills ## nix pills
From <https://nixos.org/guides/nix-pills/>: From <https://nixos.org/guides/nix-pills/>:
@ -164,27 +166,27 @@ From <https://nixos.org/guides/nix-pills/>:
## `inherit` ## `inherit`
`inherit` is a keyword in the Nix language that brings a variable into an `inherit` is a keyword in the Nix language that brings a variable into an keyed
attribute set. It can also be used in `let in`s. expression, such as an attribute set or `let in`.
Check out the Check out the
[Nix reference page](https://nixos.org/manual/nix/stable/language/constructs.html#inheriting-attributes) [Nix reference page](https://nix.dev/tutorials/nix-language.html#inherit) that
that explains the keyword in depth. explains the keyword in depth.
## `nix-tree` ## `nix-tree`
[`nix-tree`](https://github.com/utdemir/nix-tree) is a tool to interactively [`nix-tree`](https://github.com/utdemir/nix-tree) is a tool to interactively
browse dependency graphs of derivations. Made in Haskell, of course. browse dependency graphs of derivations.
## `nix-diff` ## `nix-diff`
[`nix-diff`](https://github.com/Gabriella439/nix-diff) is a tool to see how two [`nix-diff`](https://github.com/Gabriella439/nix-diff) is a tool to see how two
derivations differ with colored output. Again, in Haskell. derivations differ with colored output.
## `nix-shell -p` gives you a compiler ## `nix-shell -p` gives you a compiler
As mentioned in the `nix-shell and nix shell are completely different` section, [As mentione before](#nix-shell-and-nix-shell-are-completely-different)
`nix-shell -p` is the nixpkgs stdenv plus your packages. `nix-shell -p` is the nixpkgs stdenv plus the specified packages.
And since the stdenv includes a C compiler, so does the shell you enter after And since the stdenv includes a C compiler, so does the shell you enter after
calling `nix-shell -p hello`. calling `nix-shell -p hello`.
@ -193,19 +195,21 @@ calling `nix-shell -p hello`.
[`nix-output-monitor`](https://github.com/maralorn/nix-output-monitor), also [`nix-output-monitor`](https://github.com/maralorn/nix-output-monitor), also
known as `NOM` is a neat visualizer for Nix builds. See it in action: known as `NOM` is a neat visualizer for Nix builds. See it in action:
<https://asciinema.org/a/604200>
It is also programmed in Haskell. Whew. <script src="https://asciinema.org/a/604200.js" id="asciicast-604200" async="true"></script>
## `nix-top` ## `nix-top`
[`nix-top`] is a simple Ruby script to help people see what is building in the [`nix-top`](https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z35T5UvM72Y41aJCAUuQj1cjbaVaL)
local Nix daemon. to help people see what is building in the local Nix daemon. is a simple Ruby script to help people see what is building in the local Nix
daemon.
The original source was deleted, so I've seeded it on radicle.
## `--debugger` ## `--debugger`
The `--debugger` flag is used to halt evaulation and enter the Nix REPL when The `--debugger` flag is used to halt evaulation and enter the Nix REPL when
evaluating a Nix file or expression. evaluating a Nix expression.
You set breakpoints using the `builtins.break` function: You set breakpoints using the `builtins.break` function:
@ -214,36 +218,37 @@ let
foo = 123; foo = 123;
bar = "baz"; bar = "baz";
# Nix will stop right here, just before evaulating the attrset # Nix will stop right here, just before
# passed into `builtins.break`. We should be able to access # evaulating the attrset passed into
# `foo` and `bar`. But it doesn't work! # `builtins.break`. We are able to access
# `foo` and `bar`.
in builtins.break { in builtins.break {
inherit foo bar; inherit foo bar;
} }
``` ```
> Evaulate this file with `nix eval --debugger --file <filename>` and see. Evaulate this expression with `nix eval --debugger --expr/--file` and see.
It is also _supposed_ to bring the variables in the scope `break` was called <!-- TODO: Mention that this didn't use to work. -->
into the Nix REPL. However, this does not work. Keep on reading and you'll see
why & what do to do bypass this bug!
## `tvix` ## `tvix`
[Tvix](https://tvix.dev/) is an alternate implementation of Nix written in Rust. [Tvix](https://tvix.dev/) is an alternate implementation of Nix written in Rust.
It aims to have a modular implementation while also reusing already-written Nix It aims to have a modular implementation while also reusing already-written Nix
crates in the Rust ecosystem so other people can reuse code instead of crates in the Rust ecosystem. It is licensed under the GPLv3 license.
reimplementing it! It is licensed under the GPLv3 license.
## Eelco's Thesis It has since slowed down in development, but the [Snix](https://snix.dev/), a
fork of Tvix, still goes on.
Eelco's thesis is about The Purely Functional Software Deployment Model. Which ## eelco's thesis
Eelco's thesis is about _The Purely Functional Software Deployment Model_. Which
also happens to be about Nix. also happens to be about Nix.
You can read the thesis [here](https://edolstra.github.io/pubs/phd-thesis.pdf). You can read the thesis [here](https://edolstra.github.io/pubs/phd-thesis.pdf).
## Fixed-Output derivations do not rebuild with a changed URL ## fixed-output derivations not rebuilt with changed URL
Fixed output derivations (also called FODs) do not get rebuilt even if you Fixed output derivations (also called FODs) do not get rebuilt even if you
change any inputs passed to them (a URL string is also an input). The reason for change any inputs passed to them (a URL string is also an input). The reason for
@ -253,24 +258,35 @@ Nix will see that the output is the same, and since there already is a
derivation with the same output in the Nix store, it will assume it is cached derivation with the same output in the Nix store, it will assume it is cached
and will use that derivation. and will use that derivation.
# Tier 2: Package Maintainer Try changing the URL in the following expression and building it:
```nix
let
pkgs = import <nixpkgs> {};;
in pkgs.fetchurl {
url = "https://raw.githubusercontent.com/NixOS/nixpkgs/56d6bf5daced702e0099e3a15f0b743363ae429d/README.md";
hash = "sha256-/Lrhot+ejBBfXsPEyWtzScROLkCmdRjb4LBRcHHn+IE=";
}
```
# Tier 2: `package maintainer`
## `github:boolean-option/true` ## `github:boolean-option/true`
The [`boolean-option` GitHub organization](https://github.com/boolean-option) The [`boolean-option` GitHub organization](https://github.com/boolean-option)
allows flakes to be configured in "flake compile time". Let's say you have a allows flakes to be configured. Let's say you have a flake that provides a
flake that provides a binary. Let's also assume you can run it with the binary. Let's also assume you can run it with the following Nix CLI invokation:
following Nix CLI invokation:
```sh ```sh
nix run github:me/hello-world nix run github:me/hello-world
``` ```
This is great, you are able to run the binary. But, there is no way for a flake This is great, you are able to run the binary. But, there is no way for a flake
to accept any configuration arguments. If you wanted to run in debug mode, you to accept any configuration arguments. If you wanted to run your program in
have to create another output (like `packages.x86_64-linux.{release,debug}`). debug mode, you have to create another output (like
Same for compiling without support for X/Y/Z. This results in two to the N power `packages.x86_64-linux.{release,debug}`). Same for compiling without support for
of outputs, where N is the feature toggle count. X/Y/Z. This results in two to the N power of outputs, N being the feature toggle
count.
A dumb flake input like `github:boolean-option/true` fixes this, even though it A dumb flake input like `github:boolean-option/true` fixes this, even though it
is an ugly hack. You can do this in your flake: is an ugly hack. You can do this in your flake:
@ -293,13 +309,13 @@ is an ugly hack. You can do this in your flake:
And override the `debug-mode` input like so, to run a debug binary instead: And override the `debug-mode` input like so, to run a debug binary instead:
```sh ```sh
nix run github:me/hello-world --override debug-mode github:boolean-option/true nix run github:me/hello-world --override-input debug-mode github:boolean-option/true
``` ```
[`nix-systems`](https://github.com/nix-systems/nix-systems) is the same idea as [`nix-systems`](https://github.com/nix-systems/nix-systems) is the same idea as
`boolean-option`, but for systems instead. `boolean-option`, but for systems.
[See some example usages here.](https://github.com/search?q=boolean-option+language%3ANix&type=code&l=Nix) [Example usages.](https://github.com/search?q=boolean-option+language%3ANix&type=code&l=Nix)
These hacks wouldn't be needed if Nix allowed users to put arbitrary values in These hacks wouldn't be needed if Nix allowed users to put arbitrary values in
inputs - inputs -
@ -323,12 +339,12 @@ This results in the literal string `"export BAR_OR_BAZ=${BAR:-BAZ}"`, without
string interpolation. string interpolation.
Nix will ignore an invalid `\` escape after the `''` escape in an indent string. Nix will ignore an invalid `\` escape after the `''` escape in an indent string.
Or if it is a valid one, it will just append the `\` escape to the string, Or if the `\` escape is valid , it will just append the `\` escape to the
ignoring the `''` escape. string, ignoring the `''` escape.
## `(x: x x) (x: x x)` ## `(x: x x) (x: x x)`
This expression is a way to make Nix recurse forever and stack overflow. Nix This expression is a way to make Nix recurse forever and overflow its stack. Nix
can't detect it either, as the evaluated thunk is always different. can't detect it either, as the evaluated thunk is always different.
## Derivations are just memoized `execve` ## Derivations are just memoized `execve`
@ -450,7 +466,7 @@ explained in the man page like so:
> provided by the currently installed version of Nix. This option disables > provided by the currently installed version of Nix. This option disables
> building a new Nix. > building a new Nix.
And the `--target-host` flag is also documented (rare!), like so: And the `--target-host` flag is also documented, like so:
> Specifies the NixOS target host. By setting this to something other than an > Specifies the NixOS target host. By setting this to something other than an
> empty string, the system activation will happen on the remote host instead of > empty string, the system activation will happen on the remote host instead of
@ -468,13 +484,13 @@ And the `--target-host` flag is also documented (rare!), like so:
> the nixpkgs.crossSystem setting has to match the target platform or else > the nixpkgs.crossSystem setting has to match the target platform or else
> activation will fail. > activation will fail.
## Nix supports floats ## nix supports floats
Yup, you heard it. Nix has floats, too! Yup, you heard it. Nix has floats, too!
Though, note that not every number in Nix is a float. Integers in Nix are stored Though, note that not every number in Nix is a float. Integers in Nix are stored
as 64-bit integers. Floats are also 64-bit. as 64-bit integers. Floats are also 64-bit.
[Here's the Nix source code that denotes this](https://github.com/NixOS/nix/blob/d2a07a96ba6275e570b7d84092d08cbe85a2091b/src/libexpr/value.hh#L77-L78) [Here's the Nix source code that denotes this.](https://github.com/NixOS/nix/blob/d2a07a96ba6275e570b7d84092d08cbe85a2091b/src/libexpr/value.hh#L77-L78)
```nix ```nix
nix-repl> 0.1 + 0.2 nix-repl> 0.1 + 0.2
@ -494,11 +510,14 @@ This syntax is a way to check for the existence of a key in an attribute set.
`{ foo = 42; } ? foo` evaulates to `true`. The same applies for `{ foo = 42; } ? foo` evaulates to `true`. The same applies for
`{ foo = 42; } ? "foo"`, which is just using a string identifier instead. `{ foo = 42; } ? "foo"`, which is just using a string identifier instead.
## Flakes invented for Target Corporation You can also do `{ foo.bar = 13; } ? foo.bar`, though this isn't that well
known.
## flakes invented for Target Corporation
[The development of flakes was partially funded by Target Corporation.](https://www.tweag.io/blog/2020-07-31-nixos-flakes/#conclusion) [The development of flakes was partially funded by Target Corporation.](https://www.tweag.io/blog/2020-07-31-nixos-flakes/#conclusion)
# Tier 3: Assigned Nix Hacker at Employment # Tier 3: `assigned nix hacker at employment`
<h2> <h2>
@ -568,15 +587,16 @@ Nix converts `true` to `"1"` and `false` to `"" (empty string)` when asked to
convert a boolean to a string. convert a boolean to a string.
And when you convert a list to a string, it converts individual items and then And when you convert a list to a string, it converts individual items and then
joins them with a space character (0xA). joins them with a space character (`0xA`).
So `builtins.toString [true false true]` makes `1 1` So `builtins.toString [true false true]` makes `1 1`
## `__structuredAttrs` ## `__structuredAttrs`
`__structuredAttrs`, when set to `true` in a derivation argument, will set the `__structuredAttrs`, when set to `true` in a derivation argument, will set the
`NIX_ATTRS_JSON_FILE` and `NIX_ATTRS_SH_FILE` file paths to that arguments `NIX_ATTRS_JSON_FILE` and `NIX_ATTRS_SH_FILE` environment variables in the build
contents serialized in the respective format. environment to file paths to the derivation argument contents in the respective
format.
Here is an example: Here is an example:
@ -640,9 +660,12 @@ get something similar to this:
## `__functor` ## `__functor`
`__functor` is a magic attribute you can add on a set to make it callable. The `__functor` is a magic attribute that attribute sets can have which makes them
lambda you assign to it must "accept 2 arguments". The first being itself callable. The lambda you assign to it must accept 2 arguments[^Technically,
(commonly named "self") and the second being the argument that was passed in. lambdas in Nix always take a sigle argument. But for clarity, I'll just refere
to lambdas that return lambdas as taking `N` argument, where N is the lambda
count.]. The first being the attribute set itself (commonly named `self") and
the second being the argument that was passed in.
Here's an example: Here's an example:
@ -663,11 +686,11 @@ This outputs the following:
{ __functor = <LAMBDA>; accum = 120; } { __functor = <LAMBDA>; accum = 120; }
``` ```
(oh no - we just emulated OOP in Nix) > Oh no. We just emulated OOP in Nix!
## `--output-format bar-with-logs` on old CLI ## `--output-format bar-with-logs` on old CLI
(later renamed to `--output-format`) (later renamed to `--log-format`)
You know how the new `nix-command` CLI has that bar at the bottom, which looks You know how the new `nix-command` CLI has that bar at the bottom, which looks
like `[4/0/804 built, 7.7/112.5 MiB DL] downloading '...'`? like `[4/0/804 built, 7.7/112.5 MiB DL] downloading '...'`?
@ -681,7 +704,7 @@ This option allows you to have that output format in the old CLI by passing in
`--trace-verbose` to the Nix CLI. If you don't pass in that option, it `--trace-verbose` to the Nix CLI. If you don't pass in that option, it
completely ignores the first argument and returns the second one. completely ignores the first argument and returns the second one.
# Tier 4: Nix is Easy We Promise # Tier 4: `nix is easy we promise`
## `let f = a: a; s = {f=f;}; in [(f == f) (s == s)]` ## `let f = a: a; s = {f=f;}; in [(f == f) (s == s)]`
@ -690,9 +713,9 @@ This evaluates to `[ false true ]`. Why?
Normally, Functions in Nix cannot be compared. Comparing two functions will Normally, Functions in Nix cannot be compared. Comparing two functions will
_always_ return false, at least when done directly. _always_ return false, at least when done directly.
But if two attribute sets that are compared have the same address, Nix ignores But if two attribute sets that are compared have the same memory location, Nix
this and does a pointer comparision, totally ignoring all members. This is a ignores this and does a pointer comparision, totally ignoring all members. This
hack. is a hack.
[Link to code that does this.](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528) [Link to code that does this.](https://github.com/NixOS/nix/blob/aa165301d1ae3b306319a6a834dc1d4e340a7112/src/libexpr/eval.cc#L2525-L2528)
Here's the snippet: Here's the snippet:
@ -709,10 +732,10 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
if (&v1 == &v2) return true; if (&v1 == &v2) return true;
``` ```
This "temporary hack" was commited in 14 years ago. You can do whatever you want This "temporary hack" was commited in 15 years ago. You can do whatever you want
with this information. with this information.
## Nix Plugins ## `nix plugins`
As suprising as it sounds, Nix does indeed supports plugins. You can load As suprising as it sounds, Nix does indeed supports plugins. You can load
plugins using the plugins using the
@ -759,27 +782,76 @@ impure binaries to the Nix store.
There is a special field named `__overrides` in recursive attrset expressions, There is a special field named `__overrides` in recursive attrset expressions,
which simply overrides the parent attribute set with the keys inside it. This is which simply overrides the parent attribute set with the keys inside it. This is
different from the update operator (`//`) because that will not override the different from the update operator (`//`) because that will not override the
self-referneces in the recursive attribute set. self-refereneces in the recursive attribute set.
`rec { a = 5; b = a + 1; __overrides.a = 6; }.b` will evaluate to 7, while `rec { a = 5; b = a + 1; __overrides.a = 6; }.b` will evaluate to 7, while
`(rec { a = 5; b = a + 1; } // { a = 6; }).b` will evaluate to 6. `(rec { a = 5; b = a + 1; } // { a = 6; }).b` will evaluate to 6.
## `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` ## `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]`
As mentioned in my [HTMNIX blog post](/blog/htmnix), Nix operators get desugared Previously mentioned in my [HTMNIX blog post](/blog/htmnix), Nix operators get
into normal function calls before execution. All operators have their "hidden" desugared into normal function calls before execution. All operators have their
equivalents that they get desugared into (`__div` is for `/`, etc.), so you can "hidden" equivalents that they get desugared into (`__div` is for `/`, etc.), so
override them using `let in`. you can override them using `let in`.
`let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` is equivalent to `let __div = c: map (__mul c); in 2 / [ 1 2 3 ]` is equivalent to
`map (x: 2 * x) [ 1 2 3 ]` which evaluates to `[ 2 4 6 ]`. `map (x: 2 * x) [ 1 2 3 ]` which evaluates to `[ 2 4 6 ]`.
You can also check what a Nix snippet desugars into using You can also check what a Nix snippet desugars into using
`nix-instantiate --parse --expr 'expression here'` `nix-instantiate --parse --expr/--file`
## `let __lessThan = a: b: b - a; in 1 > 2` ## `let __lessThan = a: b: b - a; in 1 > 2`
As mentioned above, this expression will desugar into [As mentioned above](#let-div-c-map-mul-c-in-2-1-2-3-), this expression will
`let __lessThan = a: b: b - a; in __lessThan 1 2` which will evaluate to 1. desugar into `let __lessThan = a: b: b - a; in __lessThan 1 2` which will
evaluate to 1.
## `__impure` ## `__impure`
TODO
# Tier 5: `normal and can be trusted with nix`
## `let a = _: -1; or = 6; in [ a or 9 ]`
TODO
## eelco's home address is in nixpkgs
[s/used to be/is in/g.](TODO)
## `restrict-eval`
TODO
## nix2
## `__noChroot`
TODO
## cloud scale hydra
## `(_:_) != (_:_)` but `(a:a) == (a:a)`
Evaluating `(_:_) == (_:_)`, we see that it is `false`, which means the two
functions aren't equal to eachother, as we are comparing them directly and when
compared directly, functions return false.
But then why does `(a:a) == (a:a)` return `true`? Aren't they both functions?
**Nope!**
`a:a` is a
[legacy URL literal](https://nix.dev/manual/nix/2.29/development/experimental-features.html?highlight=url%20literal#no-url-literals),
which can be disabled using the `no-url-literals` Nix feature.
## de betekenis van @niksnut
TODO
## `let { huh = "?"; body = huh }`
This is the legacy `let` syntax. Equivalent to `let huh = "?"; in huh`.
## Tier 6: `has meowed before`