Hi folks!
This is a bit inspired by Rust's unwrap_or / unwrap_or_else methods.
The idea is having success(or:) / failure(or:)methods in Swift.Result to allow to lift a success or failure without running into throwing errors like exists today in get() or having to do a pattern match.
func returnsResult() -> Result<Int, any Error> {}
// current matching
func returnsDefaultValue() -> Int {
guard case let .success(success) = returnsResult() else { return 1 }
return success
}
// or even with a try?
func returnsDefaultValue() -> Int {
try? returnsValue().get() ?? 1
}
// would become instead
func returnsDefaultValue() {
returnsResult().success(or: 1)
}
The obvious advantage is in how you read this when you have multiple calls that return Result
async let request1 = service.request1().get()
async let request2 = service.request2().get()
let (response1, response2) = (
(try? await request1) ?? 1,
(try? await request2) ?? 2
)
// would become instead
async let request1 = service.request1().success(or: 1)
async let request2 = service.request2().success(or: 2)
let (response1, response2) = await (request1, request2)
Below is a quick draft in how I'm thinking:
extension Result {
/// Returns the success value contained in the `Result` enum or the value generated by the closure in case of failure
/// - Parameter otherwise: A closure that generates a value to be returned in case `Result` is a failure
/// - Returns:The success value present in `Result` or the value generated by the closure in case `Result` is a failure
@_alwaysEmitIntoClient
func success(or otherwise: () -> Success) -> Success {
guard case let .success(success) = self else { return otherwise() }
return success
}
/// Returns the success value contained in the `Result` enum or the value passed to the function
/// - Parameter otherwise: The value to be returned in case `Result` is a failure
/// - Returns:The success value present in `Result` or the value passed to the function in case `Result` is a failure
@_alwaysEmitIntoClient
func success(or otherwise: Success) -> Success {
success(or: { otherwise })
}
}
extension Result {
/// Returns the failure value contained in the `Result` enum or the value generated by the closure in case of success
/// - Parameter otherwise: A closure that generates a value to be returned in case `Result` is a success
/// - Returns:The failure value present in `Result` or the value generated by the closure in case `Result` is a success
@_alwaysEmitIntoClient
func failure(or otherwise: () -> Failure) -> Failure {
guard case let .failure(failure) = self else { return otherwise() }
return failure
}
/// Returns the failure value contained in the `Result` enum or the value passed to the function
/// - Parameter otherwise: The value to be returned in case `Result` is a success
/// - Returns:The failure value present in `Result` or the value passed to the function in case `Result` is a success
@_alwaysEmitIntoClient
func failure(or otherwise: Failure) -> Failure {
failure(or: { otherwise })
}
}
extension Result {
/// Immediately returns the success value contained in the `Result` enum or awaits the value generated by the closure in case of failure
/// - Parameter otherwise: A closure that generates a value to be returned in case `Result` is a failure
/// - Returns:The success value present in `Result` or the value generated by the closure in case `Result` is a failure
@_alwaysEmitIntoClient
func success(or otherwise: () async -> Success) async -> Success {
guard case let .success(success) = self else { return await otherwise() }
return success
}
/// Immediately returns the failure value contained in the `Result` enum or awaits the value generated by the closure in case of success
/// - Parameter otherwise: A closure that generates a value to be returned in case `Result` is a success
/// - Returns:The failure value present in `Result` or the value generated by the closure in case `Result` is a success
@_alwaysEmitIntoClient
func failure(or otherwise: () async -> Failure) async -> Failure {
guard case let .failure(failure) = self else { return await otherwise() }
return failure
}
}