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)