Skip to content

builtins.foldl' breaks lazy evaluation (is this behavior wanted?) #15625

@Zocker1999NET

Description

@Zocker1999NET

Describe the bug

I use lib.trivial.pipe from nixpkgs a lot. This is trivially implemented with foldl':
https://github.com/NixOS/nixpkgs/blob/359cc883de993d617ee36df06dbf065e39806a39/lib/trivial.nix#L150

So it came unexpected to me to discover that both functions break lazy evaluation of the intermediates.

I (now) know that this behavior is documented since #9254, and this was documented 5 years after its introduction in 61af14a.
So I tried to search for a reason for this, and have not found one in both PR/commit mentioned above.

As I have found no reason for this behavior, I want to open this issue because I think either a reason for this decision should be documented or that behavior might get changed.

Steps To Reproduce

  1. save the code below in test.nix
  2. run nix eval --file test.nix
  3. see the error "this error should not occur"
let
  pipe = builtins.foldl' (x: f: f x);
  start = [
    "hello"
    "world"
  ];
in
pipe start [
  (_: abort "this error should not occur")
  (builtins.concatStringsSep ", ")
  (_: "because this function should prevent its loading")
]

Expected behavior

Return "because this function should prevent its loading", because, in its intention, the code from above should behave the same as:

let
  start = [
    "hello"
    "world"
  ];
  func1 = _: abort "this error should not occur";
  func2 = builtins.concatStringsSep ", ";
  func3 = _: "because this function should prevent its loading";
in
func3 (func2 (func1 start))

Metadata

From both nix versions I reproduced this:

  • nix-env (Nix) 2.31.2
  • nix-env (Nix) 2.33.3

Additional context

The code from above is (of course) highly simplified. In my own code, I currently have the problem that because of the "strict" evaluation, an infinite recursion error appears when using pipe. And in that example its way more important to use a pipe construct so the code stays readable.

If for whatever reason (be it backwards compatibility now) you do not want to change this behavior, I’m fine with it. But if this behavior is decided to stay, I would be required to move to using lib.foldl (from nixpkgs) which I expect to perform way worse. And that function should then also be documented to be an explicit "fill-in" for foldl' so it does not get removed in favor of foldl'.

Checklist


Add 👍 to issues you find important.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions