4 ms·
> To seriously answer the question: is the Nix language required for the Nix packaging system to exist? Laziness is required, to some degree, but can the next i
by rssoconnor 4y ago
> To seriously answer the question: is the Nix language required for the Nix packaging system to exist? Laziness is required, to some degree, but can the next iteration provide an on-ramp which doesn't involve learning a new lang and paradigm? Guix folks sure think so.
I'd love to hear from someone deeply familiar with Nix and Guix about laziness.
I'm deeply familiar with Nix and I've concluded that lazy semantics is absolutely critical for a configuration language. It lets me refer to other attributes of my configuration from anywhere. For example, I can refer to port number from my whatever service in my firewall. Nix's system of overlays depends on laziness too to provide efficient late-binding familiar from OOP.
I don't need to topologically sort the evaluation of the various inter-dependencies of my configuration. So long as there exists an evaluation order, laziness finds it.
Laziness is compelling enough that I managed to convince the author of Jsonnet <https://jsonnet.org/ https://jsonnet.org/> of it when he was designing it, and in turn he helped me design what is now known as overlays in Nix.
I don't even understand how Guix manages to work without laziness, though clearly it does somehow. I'm curious as to how that is possible, though I fear I will only ever truly understand by diving into Guix.
- infogulch 4y agoI'm not convinced that any of the things you mentioned as benefits of lazy evaluation are a necessary condition to getting those benefits.
- WastingMyTime89 4y agoIt’s not. Guix has exactly the same properties while using an eager language.
- mikepurvis 4y agoAs an 18 month Nix packager/user, I continue to be blown away by how powerful laziness is and how expressive the interactions between multiple overlays can be.
- jackac 4y agoRecursion and merging semantics are also necessary. I use Nix and Jsonnet a lot, but Nix is much more expressive for complex structures, but the tooling being tightly coupled with the package manage make it impossible to adopt for common use cases.
- joshka 4y ago> Nix's system of overlays depends on laziness too to provide efficient late-binding familiar from OOP. As an OOPer, inheritance is one of the things that is generally trotted out as the worst aspect of OO languages. This leads to the mantra "favor composition over inheritance". Much has been written about why and how. But it seems to cause the same pain points that people talk about with respect to laziness in Nix. "Spooky action at a distance" is one of my favorite ways of describing some of these problems. (I'm not super familiar with Nix, so I could be misreading the points about laziness. Please forgive me if so.)
- rssoconnor 4y agoI actually agree with you about inheritance and OOP. It's funny because when I finally understood how to override packages with this late-binding technique, I said to myself "Finally I've found a use for inheritance!". I certainly think people should exercise caution as this could probably be abused quite badly. Maybe people will come up with better designs in the future. However I will say, that the method it has replaced was much worse. The old way was adhoc and almost always failed to achieve ones desires in all but the simplest cases. Don't just take my word for it. Peter Simons also agrees: <https://github.com/NixOS/nixpkgs/commit/3c8b33eee442fd573d47555122cfe358134aeb64 https://github.com/NixOS/nixpkgs/commit/3c8b33eee442fd573d47...>
- WastingMyTime89 4y ago> I don't need to topologically sort the evaluation of the various inter-dependencies of my configuration. So long as there exists an evaluation order, laziness finds it. That’s not a property of laziness but of how Nix evaluates configurations. I think people overvalue what laziness brings them because they attribute to it things which could be done equally well with an eager language.
- rssoconnor 4y agoThere is nothing special about how Nix evaluate system configurations that is any different from how Nix evaluates any other expression. Being able to write let usercfg = { username = "nix-user"; homedir = "/home/" + usercfg.username; }; in usercfg is nearly a hallmark of non-strict semantics, which is achieved by lazy evaluation. Strict languages can simulate these non-strict semantics by using functions of no parameters to delay evaluation, but you lose the efficiency that comes from the memoization of record fields that you get with lazy evaluation. P.S. The above would perhaps be more likely be written as rec { username = "nix-user"; homedir = "/home/" + username; } but when specifying larger configurations composed of multiple nested records with wide cross-cutting inter-dependencies, "rec" doesn't really cut it as "rec" works best with extremely local inter-dependencies.