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:
(builtins.tryEval foo) ? valuean 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.
Most helpful comment
I think a big part of the awkward design is attempting to not break purity too badly. Agree that
falseshould probably go away in favor oforbut a more genericcatchwill need to be looked at very carefully and weighed against the benefits of purity.