mirror of
https://github.com/RGBCube/Site
synced 2025-07-30 20:47:46 +00:00
Initial iceberg blog post
This commit is contained in:
parent
5d55e46c68
commit
6501413ccf
5 changed files with 519 additions and 3 deletions
|
@ -68,6 +68,17 @@ layout: base.vto
|
|||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
/* Make images fit */
|
||||
p:has(img) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Style content */
|
||||
.content {
|
||||
overflow-wrap: break-word;
|
||||
|
@ -128,7 +139,7 @@ layout: base.vto
|
|||
border: 0.15rem solid var(--foreground);
|
||||
}
|
||||
|
||||
pre:has(code) {
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
|
BIN
site/assets/nix-iceberg.webp
Normal file
BIN
site/assets/nix-iceberg.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 402 KiB |
|
@ -10,7 +10,7 @@ Are you old? Then you might want to check out my super cool
|
|||
<a href="/blog.rss">RSS Feed</a> too!
|
||||
|
||||
<ul>
|
||||
{{ for article of search.pages("type=article", "order=asc title=date")}}
|
||||
{{ for article of search.pages("type=article", "order=asc date=desc")}}
|
||||
<li>
|
||||
<p>
|
||||
<a href="{{ article.url }}">{{ article.date.toISOString().slice(0, 10) }}</a>:
|
||||
|
|
|
@ -42,7 +42,7 @@ You are somewhat correct. But not quite.
|
|||
|
||||
Nix `<foo>` expressions actually boil down to a call of the builtin `__findFile`, like so:
|
||||
|
||||
```sh
|
||||
```shell
|
||||
❯ nix-instantiate --parse --expr "<foo>"
|
||||
|
||||
(__findFile __nixPath "foo")
|
||||
|
|
505
site/blog/nix-iceberg.md
Normal file
505
site/blog/nix-iceberg.md
Normal file
|
@ -0,0 +1,505 @@
|
|||
---
|
||||
title: Explaining the Nix iceberg
|
||||
description: And revealing how cursed Nix is.
|
||||
|
||||
date: 2024-04-15
|
||||
draft: true
|
||||
|
||||
tags:
|
||||
- nix
|
||||
---
|
||||
|
||||
I was surfing the web a few weeks ago, and I came across
|
||||
this iceberg chart:
|
||||
|
||||

|
||||
|
||||
[Here's the original source for this image,
|
||||
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 depth. Let's start:
|
||||
|
||||
# Tier 1: I use NixOS (BTW)
|
||||
|
||||
## IFD blocks evaulation
|
||||
|
||||
> IFD stands for import-from-derivation.
|
||||
|
||||
IFD is when you import a Nix expression
|
||||
from a derivation in the Nix store.
|
||||
|
||||
For example:
|
||||
|
||||
```nix
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
|
||||
myNixExprDeriv = pkgs.runCommand "my-file" {} ''
|
||||
echo '{ a = "b"; }' > $out
|
||||
'';
|
||||
|
||||
mySet = import myNixExprDeriv;
|
||||
in mySet.a
|
||||
```
|
||||
|
||||
This will evaluate to `"b"`.
|
||||
|
||||
So, what are we doing in this snippet?
|
||||
|
||||
1. Importing `<nixpkgs>` and getting the packages out of it.
|
||||
2. Creating a derivation that runs an echo command, which
|
||||
writes a Nix expression to the output file.
|
||||
3. Then we import the expression, forcing the derivation to
|
||||
be realized as we accessed the contents of it.
|
||||
|
||||
> Wait, what does _realization_ mean?
|
||||
|
||||
It means to actually build a `.drv` file, using the builder,
|
||||
arguments and inputs described in it.
|
||||
|
||||
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 examples:
|
||||
|
||||
```nix
|
||||
nix-repl> pkgs = import <nixpkgs> {}
|
||||
|
||||
nix-repl> pkgs.runCommand "foo" {} "echo 'bar' > $out"
|
||||
«derivation /nix/store/h27fzbivcxw0cc1bxyyyqyivpw9rsz6k-foo.drv»
|
||||
```
|
||||
|
||||
Here, it did create a `.drv` file. But that's it. There is no
|
||||
`/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-foo` with contents
|
||||
`bar` to be seen.
|
||||
|
||||
```nix
|
||||
nix-repl> :b pkgs.runCommand "foo" {} "echo 'bar' > $out"
|
||||
|
||||
This derivation produced the following outputs:
|
||||
out -> /nix/store/rxz2bswgx6wlkdxnrcbsb503r9a67wc2-foo
|
||||
```
|
||||
|
||||
And here we force the derivation to be realized, which produces the output.
|
||||
|
||||
Where were we again? Right, the 3rd point:
|
||||
`Then we import the expression, forcing the derivation to
|
||||
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 output contents of any derivation, which in turn
|
||||
makes evaluating a Nix expression not require realizing _any_ derivations.
|
||||
|
||||
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 evaluated on a single thread and
|
||||
realizing the derivation needed takes a non-trivial amount of time.
|
||||
|
||||
TL;DR: IFD blocks evaluation because:
|
||||
|
||||
1. Evaluation is single threaded, so naturally everything blocks it.
|
||||
2. You're trying to access a derivation _output_, so obviously
|
||||
you need to realize (build) it first.
|
||||
|
||||
## `nix-shell` and `nix shell` are completely different
|
||||
|
||||
`nix-shell` is the legacy version of `nix develop`, which
|
||||
enters a devshell created by a Nix expression. It was (and
|
||||
still is) very useful.
|
||||
|
||||
People then realized getting a devshell by passing in the packages
|
||||
you wanted as command line arguments was really convenient,
|
||||
which resulted in the creation of the `--packages/-p` argument for `nix-shell`
|
||||
|
||||
`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 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
|
||||
variable. It is much lighter, as a natural result of not using the stdenv.
|
||||
It also isn't a questionable templated Nix expression and is implemented in
|
||||
the Nix CLI natively.
|
||||
|
||||
## Hydra is 17,000 lines of Perl
|
||||
|
||||
As the title says, [Hydra](http://github.com/NixOS/hydra),
|
||||
the Nix-based continuous build system is almost 17,000
|
||||
lines of Perl.
|
||||
|
||||
Here is the `tokei` output for its GitHub repository:
|
||||
|
||||
| Language | Files | Lines | Code | Comments | Blanks |
|
||||
| ---------------- | ----- | ----------- | ----- | -------- | ------ |
|
||||
| Autoconf | 2 | 38 | 37 | 0 | 1 |
|
||||
| Automake | 13 | 175 | 150 | 0 | 25 |
|
||||
| C++ | 9 | 4659 | 3448 | 406 | 805 |
|
||||
| C++ Header | 5 | 757 | 485 | 74 | 198 |
|
||||
| CSS | 3 | 505 | 388 | 35 | 82 |
|
||||
| JavaScript | 6 | 337 | 265 | 37 | 35 |
|
||||
| Nix | 38 | 2029 | 1732 | 77 | 220 |
|
||||
| Nix (Markdown) | 2 | 12 | 12 | 0 | 0 |
|
||||
| Perl | 125 | 16754 (!!!) | 12055 | 649 | 4050 |
|
||||
| Python | 1 | 35 | 25 | 1 | 9 |
|
||||
| Shell | 24 | 371 | 279 | 35 | 57 |
|
||||
| Shell (Markdown) | 1 | 3 | 2 | 1 | 0 |
|
||||
| SQL | 85 | 1406 | 989 | 202 | 215 |
|
||||
| SVG | 6 | 6 | 6 | 0 | 0 |
|
||||
| Plain Text | 4 | 164 | 0 | 102 | 62 |
|
||||
| YAML | 1 | 1137 | 1094 | 0 | 43 |
|
||||
| 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
|
||||
|
||||
From <https://nixos.org/guides/nix-pills/>:
|
||||
|
||||
> This is a ported version of the Nix Pills, a series of blog posts written
|
||||
> by Luca Bruno (aka Lethalman) and originally published in 2014 and 2015.
|
||||
> It provides a tutorial introduction into the Nix package manager and Nixpkgs
|
||||
> package collection, in the form of short chapters called 'pills'.
|
||||
>
|
||||
> Since the Nix Pills are considered a classic introduction to Nix, an effort
|
||||
> to port them to the current format was led by Graham Christensen (aka grahamc
|
||||
> / gchristensen) and other contributors in 2017.
|
||||
|
||||
## `inherit`
|
||||
|
||||
`inherit` is a keyword in the Nix language that brings a variable
|
||||
into an attribute set. It can also be used in `let in`s.
|
||||
|
||||
Check out the
|
||||
[Nix reference page](https://nixos.org/manual/nix/stable/language/constructs.html#inheriting-attributes)
|
||||
that explains the keyword in depth.
|
||||
|
||||
## `nix-tree`
|
||||
|
||||
[`nix-tree`](https://github.com/utdemir/nix-tree) is a tool to interactively
|
||||
browse dependency graphs of derivations. Made in Haskell, of course.
|
||||
|
||||
## `nix-diff`
|
||||
|
||||
[`nix-diff`](https://github.com/Gabriella439/nix-diff) is a tool to see how
|
||||
two derivations differ with colored output. Again, in Haskell.
|
||||
|
||||
## `nix-shell -p` gives you a compiler
|
||||
|
||||
As mentioned in the `nix-shell and nix shell are completely different`
|
||||
section, `nix-shell -p` is the nixpkgs stdenv plus your packages.
|
||||
|
||||
And since the stdenv includes a C compiler, so does the shell
|
||||
you enter after calling `nix-shell -p hello`.
|
||||
|
||||
## `nix-output-monitor`
|
||||
|
||||
[`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: <https://asciinema.org/a/604200>
|
||||
|
||||
It is also programmed in Haskell. Whew.
|
||||
|
||||
## `nix-top`
|
||||
|
||||
[`nix-top`] is a simple Ruby script to help people
|
||||
see what is building in the local Nix daemon. to help people
|
||||
see what is building in the local Nix daemon.
|
||||
|
||||
## `--debugger`
|
||||
|
||||
The `--debugger` flag is used to halt evaulation and
|
||||
enter the Nix REPL when evaluating a Nix file or expression.
|
||||
|
||||
You set breakpoints using the `builtins.break` function:
|
||||
|
||||
```nix
|
||||
let
|
||||
foo = 123;
|
||||
bar = "baz";
|
||||
|
||||
# Nix will stop right here, just before evaulating the attrset
|
||||
# passed into `builtins.break`. We should be able to access
|
||||
# `foo` and `bar`. But it doesn't work!
|
||||
in builtins.break {
|
||||
inherit foo bar;
|
||||
}
|
||||
```
|
||||
|
||||
> Evaulate this file with `nix eval --debugger --file <filename>` and see.
|
||||
|
||||
It is also _supposed_ to bring the variables in the scope `break`
|
||||
was called 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](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 crates in the Rust ecosystem so other people can reuse code instead of
|
||||
reimplementing it! It is licensed under the GPLv3 license.
|
||||
|
||||
## Eelco's Thesis
|
||||
|
||||
Eelco's thesis is about The Purely Functional Software
|
||||
Deployment Model. Which also happens to be about Nix.
|
||||
|
||||
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 (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 this is simple.
|
||||
|
||||
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 and will use that derivation.
|
||||
|
||||
# Tier 2: Package Maintainer
|
||||
|
||||
## `github:boolean-option/true`
|
||||
|
||||
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
|
||||
flake that provides a binary. Let's also assume you can run it with the
|
||||
following Nix CLI invokation:
|
||||
|
||||
```shell
|
||||
nix run github:me/hello-world
|
||||
```
|
||||
|
||||
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 have
|
||||
to create another output (like `packages.x86_64-linux.{release,debug}`).
|
||||
Same for compiling without support for X/Y/Z. This results in two to the N power
|
||||
of outputs, where N is the feature toggle count.
|
||||
|
||||
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:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
|
||||
debug-mode.url = "github:boolean-option/false"; # Release by default!
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, debug-mode, ... }: let
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||
in {
|
||||
packages.x86_64-linux.hello = pkgs.callPackage ./hello { inherit debug-mode; };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
And override the `debug-mode` input like so, to run a debug binary instead:
|
||||
|
||||
```shell
|
||||
nix run github:me/hello-world --override debug-mode github:boolean-option/true
|
||||
```
|
||||
|
||||
[`nix-systems`](https://github.com/nix-systems/nix-systems) is the same idea
|
||||
as `boolean-option`, but for systems instead.
|
||||
|
||||
[See some example usages here.](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
|
||||
inputs - [in fact, there is an open issue from _2021_ that is still being actively
|
||||
discussed](https://github.com/NixOS/nix/issues/5663) - but here we are.
|
||||
|
||||
## `''foo''\n'' == "foo\n"`
|
||||
|
||||
The Nix parser is very buggy, and this is one bug.
|
||||
|
||||
`''` is the character set used to escape `${` in
|
||||
Nix indent strings (No, not multiline strings! All strings in Nix
|
||||
are multiline.):
|
||||
|
||||
```nix
|
||||
''
|
||||
export BAR_OR_BAZ=''${BAR:-$BAZ}
|
||||
''
|
||||
```
|
||||
|
||||
This results in the literal string `"export BAR_OR_BAZ=${BAR:-BAZ}"`, without
|
||||
string interpolation.
|
||||
|
||||
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, ignoring the `''` escape.
|
||||
|
||||
## `(x: x x) (x: x x)`
|
||||
|
||||
This expression is a way to make Nix recurse forever
|
||||
and stack overflow. Nix can't detect it either, as the
|
||||
evaluated thunk is always different.
|
||||
|
||||
## Derivations are just memoized `execve`
|
||||
|
||||
Derivations include all required information to build themselves.
|
||||
This also includes output directories (except when they are content-addressed,
|
||||
but that is for a future blog post!). You can dump a `.drv` file as JSON with the
|
||||
`nix derivation show` command, like so:
|
||||
|
||||
<details>
|
||||
<summary>Long command output</summary>
|
||||
|
||||
```json
|
||||
❯ nix derivation show /nix/store/0aplz036lmggrryvx2xh87ci20hczijf-libsamplerate-0.1.9.drv^*
|
||||
|
||||
{
|
||||
"/nix/store/0aplz036lmggrryvx2xh87ci20hczijf-libsamplerate-0.1.9.drv": {
|
||||
"args": [
|
||||
"-e",
|
||||
"/nix/store/v6x3cs394jgqfbi0a42pam708flxaphh-default-builder.sh"
|
||||
],
|
||||
"builder": "/nix/store/bm0gsz7di3d4q0gw1kk2pa06505b0wmn-bash-5.2p26/bin/bash",
|
||||
"env": {
|
||||
"__structuredAttrs": "",
|
||||
"bin": "/nix/store/r3n9n5483q2zprrrjj0f442n723dkzyk-libsamplerate-0.1.9-bin",
|
||||
"buildInputs": "/nix/store/4rbkn1f0px39n75zbib2f43i851vy0ay-libsndfile-1.2.2-dev",
|
||||
"builder": "/nix/store/bm0gsz7di3d4q0gw1kk2pa06505b0wmn-bash-5.2p26/bin/bash",
|
||||
"cmakeFlags": "",
|
||||
"configureFlags": "--disable-fftw",
|
||||
"depsBuildBuild": "",
|
||||
"depsBuildBuildPropagated": "",
|
||||
"depsBuildTarget": "",
|
||||
"depsBuildTargetPropagated": "",
|
||||
"depsHostHost": "",
|
||||
"depsHostHostPropagated": "",
|
||||
"depsTargetTarget": "",
|
||||
"depsTargetTargetPropagated": "",
|
||||
"dev": "/nix/store/ajfrbfsqbmxb4ypnmp39xxdpg9gplxbx-libsamplerate-0.1.9-dev",
|
||||
"doCheck": "",
|
||||
"doInstallCheck": "",
|
||||
"mesonFlags": "",
|
||||
"name": "libsamplerate-0.1.9",
|
||||
"nativeBuildInputs": "/nix/store/xpah4lnaggs6qg87pg1rd9his89acprm-pkg-config-wrapper-0.29.2",
|
||||
"out": "/nix/store/55mwzr1k14mryxnhzz6z3hzaimhl8bpn-libsamplerate-0.1.9",
|
||||
"outputs": "bin dev out",
|
||||
"patches": "",
|
||||
"pname": "libsamplerate",
|
||||
"postConfigure": "",
|
||||
"propagatedBuildInputs": "",
|
||||
"propagatedNativeBuildInputs": "",
|
||||
"src": "/nix/store/9jnvkn9wcac6r62mljq9fa9vvriyib1i-libsamplerate-0.1.9.tar.gz",
|
||||
"stdenv": "/nix/store/jiz7bpw8vqzq8ncm6nn4v94qyqm9qc2p-stdenv-linux",
|
||||
"strictDeps": "",
|
||||
"system": "i686-linux",
|
||||
"version": "0.1.9"
|
||||
},
|
||||
"inputDrvs": {
|
||||
"/nix/store/356i9xqk710rnmq6y6308sv880m88r7k-pkg-config-wrapper-0.29.2.drv": {
|
||||
"dynamicOutputs": {},
|
||||
"outputs": [
|
||||
"out"
|
||||
]
|
||||
},
|
||||
"/nix/store/gfybzgm5p0hh7w7mdrz5xkr29dlsriih-libsamplerate-0.1.9.tar.gz.drv": {
|
||||
"dynamicOutputs": {},
|
||||
"outputs": [
|
||||
"out"
|
||||
]
|
||||
},
|
||||
"/nix/store/jkfhhkxlbkfhmqhaccpmqdna01wzlb42-libsndfile-1.2.2.drv": {
|
||||
"dynamicOutputs": {},
|
||||
"outputs": [
|
||||
"dev"
|
||||
]
|
||||
},
|
||||
"/nix/store/zlf7fmxbnq4k2xgngk0p953ywjqbci6f-stdenv-linux.drv": {
|
||||
"dynamicOutputs": {},
|
||||
"outputs": [
|
||||
"out"
|
||||
]
|
||||
},
|
||||
"/nix/store/zx3fgspv17raqfb859qkpqnql2fschm0-bash-5.2p26.drv": {
|
||||
"dynamicOutputs": {},
|
||||
"outputs": [
|
||||
"out"
|
||||
]
|
||||
}
|
||||
},
|
||||
"inputSrcs": [
|
||||
"/nix/store/v6x3cs394jgqfbi0a42pam708flxaphh-default-builder.sh"
|
||||
],
|
||||
"name": "libsamplerate-0.1.9",
|
||||
"outputs": {
|
||||
"bin": {
|
||||
"path": "/nix/store/r3n9n5483q2zprrrjj0f442n723dkzyk-libsamplerate-0.1.9-bin"
|
||||
},
|
||||
"dev": {
|
||||
"path": "/nix/store/ajfrbfsqbmxb4ypnmp39xxdpg9gplxbx-libsamplerate-0.1.9-dev"
|
||||
},
|
||||
"out": {
|
||||
"path": "/nix/store/55mwzr1k14mryxnhzz6z3hzaimhl8bpn-libsamplerate-0.1.9"
|
||||
}
|
||||
},
|
||||
"system": "i686-linux"
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
## `nixos-rebuild --fast --target-host`
|
||||
|
||||
The `--fast` flag in `nixos-rebuild` is an alias to `--no-build-nix`
|
||||
which is explained in the man page like so:
|
||||
|
||||
> Normally, nixos-rebuild first builds the `nixUnstable` attribute in Nixpkgs,
|
||||
> and uses the resulting instance of the Nix package manager to build the new
|
||||
> system configuration. This is necessary if the NixOS modules use features not
|
||||
> provided by the currently installed version of Nix. This option disables
|
||||
> building a new Nix.
|
||||
|
||||
And the `--target-host` flag is also documented (rare!), like so:
|
||||
|
||||
> 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 the local machine. The remote host needs to be accessible over
|
||||
> ssh, and for the commands switch, boot and test you need root access.
|
||||
>
|
||||
> If `--build-host` is not explicitly specified or empty, building will take
|
||||
> place locally.
|
||||
>
|
||||
> You can include a remote user name in the host name (user@host). You can
|
||||
> also set ssh options by defining the `NIX_SSHOPTS` environment variable.
|
||||
>
|
||||
> Note that nixos-rebuild honors the nixpkgs.crossSystem setting of the
|
||||
> given configuration but disregards the true architecture of the target
|
||||
> host. Hence the nixpkgs.crossSystem setting has to match the target platform
|
||||
> or else activation will fail.
|
||||
|
||||
## Nix supports floats
|
||||
|
||||
Yup, you heard it. Nix has floats, too!
|
||||
|
||||
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. [Here's the Nix source code that denotes this](https://github.com/NixOS/nix/blob/d2a07a96ba6275e570b7d84092d08cbe85a2091b/src/libexpr/value.hh#L77-L78)
|
||||
|
||||
```nix
|
||||
nix-repl> 0.1 + 0.2
|
||||
0.3
|
||||
|
||||
nix-repl> 0.1 + 0.2 == 0.3
|
||||
false
|
||||
|
||||
nix-repl> 0.2 + 0.2 == 0.4
|
||||
true
|
||||
```
|
||||
|
||||
## `attrset ? key` and `attrset ? "key"`
|
||||
|
||||
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"`, which is just using a string identifier instead.
|
||||
|
||||
## 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)
|
Loading…
Add table
Add a link
Reference in a new issue