The thing that is special about Nix the language is everything it doesn't have (no side effects[1], no state, no mutability). It's a very small and simple language.
Those constraints are really important for the rest of the Nix ecosystem to work.
[1]: technically there is one side effect - putting a derivation (i.e. a recipe for how to build a package) into the nix store.
The Nix language is designed for conveniently creating and composing derivations – precise descriptions of how contents of existing files are used to derive new files. It is a domain-specific, purely functional, lazily evaluated, dynamically typed programming language.
So, its key features are:
1. domain-specific: designed for conveniently creating and composing derivations. This reason alone already justifies a new language, or an embedded domain-specific language (embedded in the Guile/Scheme for guix), or a mix of both (Starlark, the build language of Bazel embedded in a restricted Python-variant).
2. purely functional: this underlies the philosophy of the Nix package manager, which aims to be purely functional (also known as hermeticity in other build systems, such as Bazel). Being purely functional in turn underlies the congruence of the NixOS operating system, where you declare what the state the system should be in (as opposed to being convergent, so that you specify how to achieve the desired state).
3. lazily evaluated: similar to other build systems (including Bazel), so that you can build only what you need on demand.
4. dynamically typed: this one is controversial. Being dynamically typed—in other words, not developing a type system—gets Nix out of the door 20 years ago. But users often complain about the lack of proper types and modularity. There are experiments to add a type-and-contract system to Nix, such as Nickel (https://github.com/tweag/nickel).
Most of the above are also listed in the Overview of the One Pager.
Is it that much of a DSL when domain-specific primitives are mostly abstracted away in a standard library written in Nix itself, with underlying machinery written in shell, and when it heavily relies on shell and foreign config snippets to do the job?
I usually don't need to write C++ when writing in JavaScript, though. Writing derivations in Nix in real world implies using the standard library and writing shell scripts for mkDerivation & co. ("domain specific" shell scripts that use stdenv)
> Nix only exists to be the language for Nix, the package manager. While people have occasionally used it for other use-cases, it is explicitly not a general-purpose language.
The next question is why is the Nix package manager needed and why should a software developer care. I don't know the answer.
Nix allows you to install packages without naming or version conflicts. It allows you to make source repositories act as first-class packages. It can be installed on any Linux distribution and MacOS. Changing and customizing packages is trivial. All the building and installing happens outside of the source tree, so you don't clutter up your $HOME. It's reproducible. It's simple. And it's build with the needs of Free Software in mind (unlike snap or flatpak which seem mostly concerned with packaging proprietary software). Also Nix is 20 years old at this point.
Simply put, with Nix I can do:
nix run github:project/name
to run a program. Not many other package managers are capable of that.
That's cool but Brew seems to work just fine for my needs (and most developers on a Mac, apparently). Which is why I think the question still stands; unclear why people should care when the status quo is good enough.
1. their home environments: for packages (some reach for brew on MacOS) and configurations (dotfiles, and some reach for stow).
2. their development shells: for build dependencies (compilers, SDKs, libraries), tools (LSP, linters, formatters, debuggers), and services (runtime, database). Some reach for devcontainers here.
3. or even their operating systems: for development, for CI, for deployment, or for personal use.
Nix provision all of the above in the same language, with Nixpkgs, NixOS, home-manager, and devShells such as https://devenv.sh/. What's more, Nix is (https://nixos.org/):
- reproducible: what works on your dev machine also works in CI and in prod,
- declarative: you version control and review your configurations and infrastructure as code, at a reasonable level of abstraction, to specify what the system should be, not how to get there,
- reliable: all changes (switching generations or profiles) are atomic with easy roll back.
Thank you, it makes sense. I guess these points would resonate with me if I had the problems you describe. Fortunately, I usually don't.
The less I fiddle with packages, dot files, shell scripts, the better my life is.
It's worth mentioning that Nix is pretty old at this point, it feels a little younger due to its recent surge in popularity. But 20 years ago (that is 8 years before v8!), the programming languages market looked quite different from today.
Guix shows that it's possible to use a different frontend language technically, but switching the nixpkgs repo itself over to anything else at this point would be an enormous community effort where it's hard to say whether it's worth it.
Yeah. I guess the answer is that there weren't (m)any configuration languages which had functions - even YAML itself (which doesn't have functions) came out a few years before nix. Cue, starlark, dhall are all much later.
It's not really a programming language. It's a lot like JSON except with lambda functions and variables. Compared to the "template yaml" monstrosity gifted to us by the pointy-haired corporations, the Nix language makes a thousand times more sense.
The common joke/fact in the nix community is the nix "triad": nix the language, nix the operating system, and nix the package manager. Sometimes it gets confusing, but usually context is enough.
Except that Nix ≠ NixOS, which it seemed was very clear to everyone for a very long time.
Recently some Linux hobbyists new to the Nix community have started using the word 'Nix' to refer to NixOS, which is wrong and has understandably led to quite some confusion. I wish they'd stop fucking it up.
A restricted purely functional language for configuration is a great idea. But why not a lisp? The syntax is well thought out, but who needs to remember yet another set of syntax rules. And it's not like lisp syntax would scare off the Nix crow anymore than it scared off the Emacs crowd.
I considered guix, but they seem a bit more religious about non-free. It might be cool to create a lisp->nix transpiler, but nixpkgs is in nix, and you spend a lot of time reading that when doing anything nix.
Their software freedom policy seems to be similar to Debian. All free by default, allow separate nonfree addon. In the case of Guix you can find that here: https://gitlab.com/nonguix/nonguix .
> Please do NOT promote this repository on any official Guix
communication channels, such as their mailing lists or IRC channel, even in
response to support requests! This is to show respect for the Guix project’s
strict policy
against recommending nonfree software, and to avoid any unnecessary hostility.
Syntax-wise it's about as similar to JSON as Erlang expressions are (i.e. superficially similar in some cases).
Semantics-wise I've personally found any superficial similarity to JSON to be actively unhelpful in understanding because of some important processing differences (e.g. paths, laziness).
Agreed. I've tried to write a json-nix converter (because I wanted to try configuring my system in jsonnet) and it's absolutely not easy, or obvious how to do this.
The FunctionalScript language is supposed to be a superset of JSON and a subset of Javascript that's pure and functional. Not sure that's suited to the use case Nix is going for, but that sounds like what we'd get if we took the extended-JSON path.
First a minor quibble: if you're talking about 'Nix data', then starting the conversation by talking about 'Nix-the-language' is rather misleading.
That aside, Nix allows you to create infinite datastructures, e.g.
$ nix eval --expr 'rec { z = { a = z; i = 5; }; }.z.a.a.a.i'
5
which you can't do with JSON.
But even if JSON did have some way of handling datastructure 'loops', it's still not helpful because of laziness. You almost never want to eagerly evaluate a Nix expression to produce what you seem to term 'Nix data', because you'll invoke the `derivation` built in function to create paths you never actually reference - this is why laziness is such an important property of Nix.
So I'm still not clear what user-facing part of Nix is isomorphic to JSON. If it's just "Nix types [0] are similar to JSON types" then...sure.
As a NixOs lover and user, nix-the-language is my least loved feature of the ecosystem. But at a user is not a big problem because I only write configurations for myself, and it's not like my OS configuration is a proper program, it's closer to data.
One upside is that because it's hard to write complex programs in nix, people don't do it (unless really needed). So the nixos tutorials and configuration examples on the internet are usually pretty simple. This is good for beginners, and nixos is already a huge undertaking.
With lisp I'm sure many of us would get crazy with abstractions.
I should point out that Nix exists as an independent Linux Package Manager (hereafter referred to as "The Nix Package Manager") -- completely separate from NixOS and the Nix Programming Language...
That is, The Nix Package Manager can be used independently of NixOS or The Nix Programming Language to install software on any Linux system (or MacOS) from the Nix Package Repository (search it at: https://search.nixos.org/packages) regardless of any knowledge (or any lack of knowledge!) that a given user has (or doesn't have!) of the Nix Programming Language...
Here's how to install it on a non-NixOS system (top half of page):
The idea of running another Linux distro's package manager/installer to install things from their repository onto your Linux distro is not a new one -- in fact, it has been done rather successfully on many Linux distros for some time...
This concept invariably brings us to Bedrock Linux, a distribution whose sole purpose is to run package managers/installers -- from other distros!
Still, if not perfect in the current day, the idea of being able to mix-and-match package managers/installers from multiple Linux distros/repositories -- is a very compelling one!
Both the Nix and the Bedrock teams should be highly lauded for their efforts! Nix to create hermetic software environments, Bedrock to mix-and-match (and sort out compatibility issues!) between multi distro package managers/installers and software repositories...
Both are worth a serious look -- and potentially some of your time!
41 comments
[ 1.8 ms ] story [ 101 ms ] threadThose constraints are really important for the rest of the Nix ecosystem to work.
[1]: technically there is one side effect - putting a derivation (i.e. a recipe for how to build a package) into the nix store.
1. domain-specific: designed for conveniently creating and composing derivations. This reason alone already justifies a new language, or an embedded domain-specific language (embedded in the Guile/Scheme for guix), or a mix of both (Starlark, the build language of Bazel embedded in a restricted Python-variant).
2. purely functional: this underlies the philosophy of the Nix package manager, which aims to be purely functional (also known as hermeticity in other build systems, such as Bazel). Being purely functional in turn underlies the congruence of the NixOS operating system, where you declare what the state the system should be in (as opposed to being convergent, so that you specify how to achieve the desired state).
3. lazily evaluated: similar to other build systems (including Bazel), so that you can build only what you need on demand.
4. dynamically typed: this one is controversial. Being dynamically typed—in other words, not developing a type system—gets Nix out of the door 20 years ago. But users often complain about the lack of proper types and modularity. There are experiments to add a type-and-contract system to Nix, such as Nickel (https://github.com/tweag/nickel).
Most of the above are also listed in the Overview of the One Pager.
How is using (nix?) standard library something that you don't want?
The next question is why is the Nix package manager needed and why should a software developer care. I don't know the answer.
Simply put, with Nix I can do:
to run a program. Not many other package managers are capable of that.1. their home environments: for packages (some reach for brew on MacOS) and configurations (dotfiles, and some reach for stow).
2. their development shells: for build dependencies (compilers, SDKs, libraries), tools (LSP, linters, formatters, debuggers), and services (runtime, database). Some reach for devcontainers here.
3. or even their operating systems: for development, for CI, for deployment, or for personal use.
Nix provision all of the above in the same language, with Nixpkgs, NixOS, home-manager, and devShells such as https://devenv.sh/. What's more, Nix is (https://nixos.org/):
- reproducible: what works on your dev machine also works in CI and in prod,
- declarative: you version control and review your configurations and infrastructure as code, at a reasonable level of abstraction, to specify what the system should be, not how to get there,
- reliable: all changes (switching generations or profiles) are atomic with easy roll back.
Guix shows that it's possible to use a different frontend language technically, but switching the nixpkgs repo itself over to anything else at this point would be an enormous community effort where it's hard to say whether it's worth it.
> No, NixOS is a Linux distribution that utilizes these
My mistake!
NixOS is just a barebones Linux distro which uses the nix package manager for system configuration
Recently some Linux hobbyists new to the Nix community have started using the word 'Nix' to refer to NixOS, which is wrong and has understandably led to quite some confusion. I wish they'd stop fucking it up.
Hah, I wonder why I didn't come across it before.
Syntax-wise it's about as similar to JSON as Erlang expressions are (i.e. superficially similar in some cases).
Semantics-wise I've personally found any superficial similarity to JSON to be actively unhelpful in understanding because of some important processing differences (e.g. paths, laziness).
That aside, Nix allows you to create infinite datastructures, e.g.
which you can't do with JSON.But even if JSON did have some way of handling datastructure 'loops', it's still not helpful because of laziness. You almost never want to eagerly evaluate a Nix expression to produce what you seem to term 'Nix data', because you'll invoke the `derivation` built in function to create paths you never actually reference - this is why laziness is such an important property of Nix.
So I'm still not clear what user-facing part of Nix is isomorphic to JSON. If it's just "Nix types [0] are similar to JSON types" then...sure.
[0] https://nixos.org/manual/nix/stable/language/values
One upside is that because it's hard to write complex programs in nix, people don't do it (unless really needed). So the nixos tutorials and configuration examples on the internet are usually pretty simple. This is good for beginners, and nixos is already a huge undertaking.
With lisp I'm sure many of us would get crazy with abstractions.
That is, The Nix Package Manager can be used independently of NixOS or The Nix Programming Language to install software on any Linux system (or MacOS) from the Nix Package Repository (search it at: https://search.nixos.org/packages) regardless of any knowledge (or any lack of knowledge!) that a given user has (or doesn't have!) of the Nix Programming Language...
Here's how to install it on a non-NixOS system (top half of page):
https://nixos.org/download/
(Basically just "$ sh <(curl -L https://nixos.org/nix/install) --daemon" for multi-user setup, or "$ sh <(curl -L https://nixos.org/nix/install) --no-daemon" for single-user setup...)
The idea of running another Linux distro's package manager/installer to install things from their repository onto your Linux distro is not a new one -- in fact, it has been done rather successfully on many Linux distros for some time...
This concept invariably brings us to Bedrock Linux, a distribution whose sole purpose is to run package managers/installers -- from other distros!
https://bedrocklinux.org/index.html
...Or at least attempt to!
That's because some distros/package managers/Linux software -- may create conflicts with other installers/package managers/Linux software...
As can be seen here, from these Bedrock compatibility charts/"compatibility matrices":
https://bedrocklinux.org/0.7/distro-compatibility.html
https://bedrocklinux.org/0.7/feature-compatibility.html
Still, if not perfect in the current day, the idea of being able to mix-and-match package managers/installers from multiple Linux distros/repositories -- is a very compelling one!
Both the Nix and the Bedrock teams should be highly lauded for their efforts! Nix to create hermetic software environments, Bedrock to mix-and-match (and sort out compatibility issues!) between multi distro package managers/installers and software repositories...
Both are worth a serious look -- and potentially some of your time!