Add `ResultFailureException` and `T.fail` convenience API
The T.fail shortcut is an experiment. Pease comment WDYT.
This change was discussed in https://github.com/com-lihaoyi/mill/pull/3406
I'd also like to remove the Exception from Result.Failing hierarchy,
but it was added before the last stable release, so this would be
considered a binary incompatible change.
The test covering this task:
def sometimesFailingWithException(fail: Boolean): Task[String] = T.task {
if (!fail) "Success"
else T.fail("Failure")
}
fails with
X mill.eval.SeqTaskTests.sometimeFailingWithException.failure 2ms
java.lang.AssertionError: assertion failed: ==> assertion failed: Left(mill.api.ResultFailureException: Failure
mill.api.Ctx$Fail.fail(Ctx.scala:109)
mill.api.Ctx$Fail.fail$(Ctx.scala:109)
mill.api.Ctx.fail(Ctx.scala:124)
mill.define.Target$.fail(Task.scala:199)
mill.eval.TaskTests$Build.$anonfun$sometimesFailingWithException$1(TaskTests.scala:129)
mill.define.Task$TraverseCtx.evaluate(Task.scala:71)) != Left(mill.api.Result$Failure)
scala.Predef$.assert(Predef.scala:279)
utest.asserts.Asserts$ArrowAssert.$eq$eq$greater(Asserts.scala:90)
mill.eval.TaskTests.$anonfun$tests$44(TaskTests.scala:285)
mill.eval.TaskTests.$anonfun$tests$44$adapted(TaskTests.scala:284)
mill.eval.SeqTaskTests$.withEnv(TaskTests.scala:296)
mill.eval.TaskTests.$anonfun$tests$43(TaskTests.scala:149)
So, I wonder why?
The T.task macro expects a Result[T], but I return a not-Result-type, so I think the compiler should apply the implicit Result.create method, which surrounds the t: => T with a try-catch-block to lift the ResultFailureException thrown by T.fail into a Result.Failure. Yet, it's obviously not working as I think it should. Any ideas?
Instead of converting to a Result.Failure you could add a rule to pretty print the error message as I did in the other PR for Result.Exception(Result.Failure) but for Result.Exception(ResultFailureException)
What do you think?
Instead of converting to a
Result.Failureyou could add a rule to pretty print the error message as I did in the other PR forResult.Exception(Result.Failure)but forResult.Exception(ResultFailureException)What do you think?
The idea is, to keep the control flow of tasks returning results functional. I still have this idea in my mind, that we one day can recover from failed tasks (https://github.com/com-lihaoyi/mill/discussions/1779), but that's only possible if we stick to a uniform way of failing.
I think this approach looks fine by me
This PR is still in draft state, since there is one open issue: https://github.com/com-lihaoyi/mill/pull/3422#issuecomment-2315741498. Has an fix or an idea?
Superseded by https://github.com/com-lihaoyi/mill/pull/4964