fcd5e53703
When investigating discrepancies between foldl' in tvix and C++ Nix, I discovered that C++ Nix's foldl' doesn't seem to be strict at all. Since this seemed wrong, I looked into Haskell's foldl' implementation which doesn't force the list elements (`val` in our code), but the accumulation value (`res` in our code). You can look at the code here: https://hackage.haskell.org/package/base-4.17.0.0/docs/src/GHC.List.html#foldl%27 This actually makes a lot of sense: If `res` is not forced after each application of `op`, we'll end up thunks nested as deeply as the list is long, potentially taking up a lot of space. This can be limited by forcing the `res` thunk before applying `op` again (and creating a new thunk). I've also PR-ed an equivalent change for C++ Nix at https://github.com/NixOS/nix/pull/7158. Since this is not merged nor backported to our Nix 2.3 fork, I've not copied the eval fail test yet, since it wouldn't when checking our tests against C++ Nix in depot. Change-Id: I34edf6fc3031fc1485c3e714f2280b4fba8f004b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6947 Autosubmit: sterni <sternenseemann@systemli.org> Reviewed-by: grfn <grfn@gws.fyi> Tested-by: BuildkiteCI
2.1 KiB
2.1 KiB
Nix language issues
In the absence of a language standard, what Nix (the language) is, is prescribed by the behavior of the C++ Nix implementation. Still, there are reasons not to accept some behavior:
- Tvix aims for nixpkgs compatibility only. This means we can ignore behavior in
edge cases nixpkgs doesn't trigger as well as obscure features it doesn't use
(e.g.
__overrides
). - Some behavior of the Nix evaluator seems to be unintentional or an implementation detail leaking out into language behavior.
Especially in the latter case, it makes sense to raise the respective issue and maybe to get rid of the behavior in all implementations for good. Below is an (incomplete) list of such issues:
- Behaviour of nested attribute sets depends on definition order
- Partially constructed attribute sets are observable during dynamic attr names construction
- Nix parsers merges multiple attribute set literals for the same key incorrectly depending on definition order
- builtins.foldl' doesn't seem to be strict
On the other hand, there is behavior that seems to violate one's expectation about the language at first, but has good enough reasons from an implementor's perspective to keep them:
- Dynamic keys are forbidden in
let
andinherit
. This makes sure that we only need to do runtime identifier lookups forwith
. More dynamic (i.e. runtime) lookups would make the scoping system even more complicated as well as hurt performance. - Dynamic attributes of
rec
sets are not added to its scope. This makes sense for the same reason. - Dynamic and nested attributes in attribute sets don't get merged. This is a tricky one, but avoids doing runtime (recursive) merges of attribute sets. Instead all necessary merging can be inferred statically, i.e. the C++ Nix implementation already merges at parse time, making nested attribute keys syntactic sugar effectively.