# Nix Talk and Train
## Disclaimer
Nix has a steep learning curve. If you bear with us through it, we promise there’s really cool stuff we’ve implemented and much more cool stuff we can implement when everyone is on board.
## What is Nix?

### The Before-Times: tarballs and system package managers
- Install libs to /usr/lib. What’s the problem?
- Automate with your system package manager: apt/pacman/yum/whatever
- If different projects require different versions, your screwed.
### Javascript inovations
- These may not have originated with Javascript but it’s where I learned them.
- local ./node_modules folder
- nvm - support many version of nodejs simultaneously
- yarn.lock and package-lock.json - reproducible package resolution, but only works for npm packages.
### Docker to Rescue
- chroot into encapsulated environments
- hash “image layers” so they are shareable across machines
- Dockerfiles greatly standardize build steps
- image layers form a single stack - if you need dependencies from multiple stacks, you’re out of luck
### Easier times with Esy
- Keep the chroot idea from docker
- But make build plans composable - you can pull in many separate esy files
- Perfectly reproducible except when you rely on system packages
- JSON configuration language - very easy, very low leverage.
- Tiny community - very few packages.
## Enter Nix
- Package manager that does chrooted environments like docker
- Allows describing complex build plans that form DAG’s like Esy
- Constructs these build plans in a Turing complete language with a monad called a “derivation”
- The language is purely functional so the same inputs always output the same derivations
- The language is lazy to allow huge libraries of packages (ex: Debian package repository has 60,000 packages - you don’t want to have evaluate all that at once every time).
- The language is dynamically typed to allow more concise expressions, but (they’re working on a gradually typed extension to the language called Nickel (Nickel can compile down to nix), because it turns out working without types is hard).
### What does Nix buy you?
- Perfect reproducibility (pretty darn close anyway, see https://r13y.com/)
- Caching - transport your build cache to any machine of the same architecture and never build the same package twice.
- Leverage! Use functional programming to powerfully transform packages.
- Package repository = just a library. Nixpkgs is the central package repository for nix, but it’s just a giant library of derivations.
- Allow multiple versions of a package to coexist in harmony in your dependency DAG.
## Comparison
| feature | system package manager | opam | docker | esy | nix |
|------------------------|------------------------|------------------|----------------------|---------------|----------------------------------------|
| reproducibility | VERY POOR | Poor | Poor, but also great | Great | Almost Perfect (see https://r13y.com/) |
| dependency graphs | DAG | DAG | linear | DAG | DAG |
| Dependency hell | WORST | Bad | N/A | Almost solved | Solved |
| Mutability | mutable hell | mutable switches | immutable | immutable | immutable |
| Configuration language | Bash/??? | Opam files | Dockerfiles | JSON | Nix expressions (Turing complete) |
| Caching | very poor | poor | poor | great | great |
| Learning curve | easy | medium | medium | easy | steep |
## Nix language
**Strings**
```nix
a = "foo";
b = ''bar''; # same as above but allows multi-line strings
c = "${a} - ${b}"; # -> "foo - bar";
```
**Records**
*Usually called "Atrribute sets" in nix*
```nix
{
foo = "bar";
baz = "qux";
}
```
**let expressions**
```nix
let
a = "foo";
in
a
```
**Functions**
```nix
let
add = a: b: a + b;
in
add 1 2
# 3
```
```
let
add = a: b: a + b;
add2 = add 2;
in
add2 3
# 5
```
Extra material, [nix-pills](https://nixos.org/guides/nix-pills/basics-of-language.html) is a repl based tutorial, the [manual](https://nixos.org/manual/nix/stable/expressions/writing-nix-expressions.html) has a very good section as well.
## Nixpkgs
- https://search.nixos.org
## Exercises
First exercise:
```nix
nix --experimental-features "nix-command flakes" flake new hello-ocaml -t github:marigold-dev/nix-templates#hello-ocaml
```
Second exercise:
```nix
nix --experimental-features "nix-command flakes" flake new hello-ocaml-dream -t github:marigold-dev/nix-templates#hello-ocaml-dream
```
### Questions:
- do you mean you'd have to rewrite the whole Dockerfile ?
- Yes, since you can't do "FROM ... AND ..."
- why poor reproducibility for opam ? because proper maintenance of opamfile is a pain ?
- opam only packages OCaml packages, esy has sandboxing so you endup packaging a lot of C dependnecies
- flakes is flagged as experimental: what does it means? unstable? may disapear in a snap?
- The API is unstable but they are not breaking you between versions
- How do you warranty that the package on nixPkg is the same as the one in opam?
- Short answer: you don't
- Longer answer, nixpkgs has 1 version of every package (there are pacakges that doesn't follow this however), but you can change the package via overlays which we'll discuss later
- Who is running nixPkg? Managing publication? What is the workflow? =>
- https://github.com/NixOS/nixpkgs
- Open PR, people will check it and merge if it's OK.
- Then it will get built by hydra and included in a "channel" (branch)
- Is there any official organization? (who are you trusting when using nixPkg)
- You can just read the code for trust
- (not about code, it is about how & who you trust when you download & run a lib) => very important if you ship actual product
- Isn't it the same with opam?
- there is OCaml Foundation nowadays
- There is also a restrictic workflow
- Sure someone can ship shit and make you run it, but OCaml community is "watching" / if you duplicate, who do you trust?
- There is no company behind it, but Tweag and Serokell are heavy users
- There is some money that pays for infrastructure
- How to crossCompile hello?
- Out of scope, but we can show it in Deku
- how fat does the nix local dir becomes before it more or less stabilize because you've already built / pulled everything ?
- Define everything
- what you usually need for normal work ? (not a very strict definition)
- You will probably have multiple ocaml compilers + packages for each compiler since different projects needs different versions so this adds up, but maybe 20-50GiB depending on what you do
- Sometimes when building I want to have cool macros that interact with the outside world (like fetching openapi specs from the internet and things like this), are things like that possible when everything is hermetically sealed?
- possible : you check with hash what you fetch from the internet to make it pure (?)
- What does `inputs.<name>.inputs.<name>.follows` mean?
- What is actually sandboxed ?