Nix: Remove value for failed tryEval?

Created on 14 Sep 2018  路  6Comments  路  Source: NixOS/nix

Currently, tryEval will insert the fairly arbitrary value false for failed evaluations:

nix-repl> builtins.tryEval 5
{ success = true; value = 5; }

nix-repl> builtins.tryEval (throw "nope")
{ success = false; value = false; }

The most common use case (I'm guessing) for tryEval is to provide an alternative value should evaluation fail. This is rather cumbersome with its current behaviour:

nix-repl> let result = builtins.tryEval 5; in if result.success then result.value else "failed"
5

nix-repl> let result = builtins.tryEval (throw "nope"); in if result.success then result.value else "failed"
"failed"

It would be a lot more convenient thanks to the or keyword (and less arbitrary) not to have the value key at all for unsuccessful evaluation:

nix-repl> newTryEval = x: let r = builtins.tryEval x; in if r.success then r else { success = false; }

nix-repl> (newTryEval 5).value or "failed"
5

nix-repl> (newTryEval (throw "nope")).value or "failed"
"failed"

Some further thoughts:

  • with the suggested change, the success key isn't really necessary any more and could be replaced by (builtins.tryEval foo) ? value
  • an improved tryEval could potentially include the error message or other details to make it more versatile

Most helpful comment

I think a big part of the awkward design is attempting to not break purity too badly. Agree that false should probably go away in favor of or but a more generic catch will need to be looked at very carefully and weighed against the benefits of purity.

All 6 comments

an improved tryEval could potentially include the error message or other details to make it more versatile

+1 to that

But how about adding a more proper error handling machanism:

builtins.catch (throw "foo") (e: "Got error: ${e}") -> "Got error: foo"
builtins.catch "foo" (e: "Got error: ${e}") -> "foo"

Would be much more ergonomic than tryEval.

I think a big part of the awkward design is attempting to not break purity too badly. Agree that false should probably go away in favor of or but a more generic catch will need to be looked at very carefully and weighed against the benefits of purity.

For the record continuity: https://github.com/NixOS/nix/pull/1000#issuecomment-235872787

I do agree that with or and ? it is a good idea to drop value from failed attempts, then after the old Nix version falls out of support we can decide on dropping success.

Since it's a fairly trivial change, I've opened #2424 implementing just the "remove value on failure" change.

Looked at Nixpkgs. Hm, there are some cases where lack of value would be slightly annoying. Dunno how many such out-of-tree uses are.

An alternative meaning for value is to re-throw the original exception, but this could be added later as an extra attribute valueOrException. With a separate attr, you can still do .value or foo.

Re purity: we could add a primop to modify the message or even combine exception messages from two expressions. Such a primop does not leak the message to the 'normal' execution, because it doesn't allow its caller to catch the exception.

Was this page helpful?
0 / 5 - 0 ratings