Is there any real reason that Nix or Guix *need* to be functional?

Pretty much the title. I am curious as to why this is the case. Is there any real reasoning behind being a functional language or benefits that complement the reproducible nature nicely? or is this just an arbitrary design choice?

Lazy evaluation has been pretty helpful in creating package sets and the module system. Nix doesn’t need to be functional, but functional languages work pretty well with Nix’s goals and requirements.

5 Likes

To avoid impurities and enforce “correct” deployments, software packaging should be described in terms of pure functions. This does not necessitate using a functional PL, and Eelco says as much in his thesis. However he did mention that using a functional language simply made it easier to describe certain ideas. And of course this was 2003, we have many other langs at our disposal now that might be more suitable.

Though, do read it and form your own conclusions.

4 Likes

@zombiezen has been playing with generating .drvs using Lua, if I remember correctly: Zombie Zen - zb: A Build System Prototype

1 Like

I’m going to assume you meant “pure functional” language – i.e. deterministic with no side effects.

  • The nix-build process state and sandbox ensure that build-time computation has no side effects and is (reasonably) deterministic.

  • A pure functional eval language is necessary in order to ensure that eval-time computations have no side effects and are deterministic.

Until very very recently, Guix used the same nix-build and sandbox that nix does, which gave them side-effect-free deterministic behavior at build time. However because Guix uses an impure language (Scheme) for eval, they’ve never had that property end-to-end for the whole build process including eval.

This was the dealbreaker for me when I tried switching to Guix.

Minor caveats regarding side effects"Side effect free" is understood as treating `/nix/store` the same way the heap is treated in, say, Haskell. Allocating heap objects isn't a side effect in Haskell. With respect to determinism, `restrict-eval` is assumed, any path references in a nix file are considered implicit arguments (along with `uname -sm` to populate `builtins.currentSystem`).

In theory you could ensure determinism and no side effects it by hand – assuming you never make any mistakes.

You could also could write security-critical software in assembly language – assuming you never make any mistakes. I don’t recommend doing this.

2 Likes