heterogenous `or`

Useful for translating `error` results
This commit is contained in:
Jacek Sieka 2020-05-08 12:16:07 +02:00 committed by zah
parent 638e7acc8e
commit 2d9226464d
2 changed files with 31 additions and 7 deletions

View File

@ -373,15 +373,29 @@ template `and`*[T0, E, T1](self: Result[T0, E], other: Result[T1, E]): Result[T1
if s.o:
other
else:
type R = type(other)
R.err(s.e)
when type(self) is type(other):
s
else:
type R = type(other)
err(R, s.e)
template `or`*[T, E](self, other: Result[T, E]): Result[T, E] =
## Evaluate `other` iff not self.isOk, else return self
## fail-fast - will not evaluate other if a is a value
template `or`*[T, E0, E1](self: Result[T, E0], other: Result[T, E1]): Result[T, E1] =
## Evaluate `other` iff `not self.isOk`, else return `self`
## fail-fast - will not evaluate `other` if `self` is ok
##
## ```
## func f(): Result[int, SomeEnum] =
## f2() or err(EnumValue) # Collapse errors from other module / function
## ```
let s = self
if s.o: s
else: other
if s.o:
when type(self) is type(other):
s
else:
type R = type(other)
ok(R, s.v)
else:
other
template catch*(body: typed): Result[type(body), ref CatchableError] =
## Catch exceptions for body and store them in the Result

View File

@ -35,6 +35,9 @@ doAssert (rErr or rOk).isOk
# `and` heterogenous types
doAssert (rOk and rOk.map(proc(x: auto): auto = $x))[] == $(rOk[])
# `or` heterogenous types
doAssert (rErr or rErr.mapErr(proc(x: auto): auto = len(x))).error == len(rErr.error)
# Exception on access
let va = try: discard rOk.error; false except: true
doAssert va, "not an error, should raise"
@ -182,6 +185,13 @@ doAssert testQn()[] == 0
doAssert testQn2().isErr
doAssert testQn3()[]
proc heterOr(): Result[int, int] =
let value = ?(rErr or err(42)) # TODO ? binds more tightly than `or` - can that be fixed?
doAssert value + 1 == value, "won't reach, ? will shortcut execution"
ok(value)
doAssert heterOr().error() == 42
type
AnEnum = enum
anEnumA