In every Swift project, I find myself needing this function:
extension Optional {
func orThrow<E: Error>(
_ error: @autoclosure () -> E
) throws(E) -> Wrapped {
guard let wrapped = self else {
throw error()
}
return wrapped
}
}
I'd like to propose adding this API to the stdlib, so you can write
let thing = optionalThing.orThrow(MyError.missingThing)
Which is often more useful than the more verbose,
guard let thing = optionalThing else {
throw MyError.missingThing
}
For example, where several things are optional:
try myFunction(
a: optionalA.orThrow(MyError.missingA),
b: optionalB.orThrow(MyError.missingB),
c: optionalC.orThrow(MyError.missingC)
)
it's a lot more succinct and easier to follow than the solution with guard:
guard let a = optionalA else {
throw MyError.missingA
}
guard let b = optionalB else {
throw MyError.missingB
}
guard let c = optionalC else {
throw MyError.missingC
}
myFunction(a: a, b: b, c: c)
Random thoughts:
The name, obviously, is not the only possibility. That's the name I choose, and the name I found already present when I joined my current job, but eg. unwrap(orThrow:) might be another good option.
Pointfreeco use a slightly different formulation, that I think is less flexible, and wouldn't cover some of the cases I use it for:
extension Optional {
struct Nil: Error {}
public func unwrap() throws -> Wrapped {
guard let unwrapped = self else { throw Nil() }
return unwrapped
}
}
Proposing the addition of this function raises the question of whether we should also add the missing Optional to Result conversion for completeness:
From To  |
Optional<T> |
Result<T, E> |
throws(E) -> T |
Optional<T> |
n/a |
|
(opt.orThrow(e) proposed above) |
Result<T, E> |
try? result.get() |
n/a |
result.get() |
throws(E) -> T |
try? f() |
Result { try f() } |
n/a |
(you could also reasonably add Bool to this table, in which case there's a few more missing conversions)