I program in a half-dozen common languages and read ten more, and have been doing so for decades and the Nix DSL still confuses me. I would not say it is fairly simple.
Perhaps this will change with more doc reading, but it is anything but intuitive (coming from a C, Perl, Java, JS, PHP, Python, Go, et c background).
Other languages were deemed too big, especially in 2003 when Nix was started. Nix is a strict diet. Perhaps something else could be used, but I can assure you Nixpkgs would be a completely failed experiment drowning in its own complexity if there were side effects.
Also, I don't understand how people can say the semantics is fine but the syntax is challenging. Syntax is entirely superficial. And if you are having trouble reading the syntax, how can you be sure the semantics isn't challenging?
There are a lot of funny fixed points used in Nixpkgs and that is challenging to think about.
The Nix properties fit ideally with the domain it tries to solve:
- functional with no side effects (for the same imput you always supposed to get the exact same output); derivation is function of its inputs (e.g. source code, dependencies, compiler flags, architecture and so on) if none of them changes you're expecting to get the same file. Introducing side effects would remove this guarantee, and introduce bugs.
- lazily evaluated - you can specify multiple things but Nix will process only the ones that are referenced, this makes weird experience that the code isn't executed from top to bottom (as most people would expect)
Those two things essentially makes the derivation declarative. You specify what derivation you want and what it needs (like dependencies) you can also use the language to transform the inputs to the way you like and still preserving the guarantee that if one dependency changes the project needs to be rebuilt.
Those are all the same language, that are different dialects of each other. Conceptually they are all very similar, and once you know one well, you understand %90 of the other ones. Java, C & Golang are the only ones that are bit different with static typing, manual memory management (C) and language level concurrency.
Nix DSL, Haskell, OCaml, declarative UI libraries, Rx and other declarative paradigms are fairly different and do require a bit of new learning. They go way beyond functional programing basics like map and filter.
I can't disagree more. All of the languages you have listed are well known for having complex semantics. This is totally expected of any general purpose programming language, of course. But the Nix expression language, though Turing-complete, isn't meant to be a general purpose programming language. It's a configuration DSL for defining packages. As such, it has a much smaller feature set with fewer confusing semantics.
The Nix expression language is in essence just JSON with functions comprising of the following building blocks:
Bazel has starlark, which is reduced python, which I've found in practice fairly easy to understand. Do you think the nix DSL could of been replaced with bazel's model of doing things and would meet the same functionality? I'm not very familiar with nix.
Perhaps this will change with more doc reading, but it is anything but intuitive (coming from a C, Perl, Java, JS, PHP, Python, Go, et c background).