Typed throw functions

Yes this is the hardest case of all. And I added it yesterday. :smiley: I'm more and more convinced that we need to take error conversions into account when we write this proposal. We need to think it through before updating throws

But I disagree that nothing would improved by it comparing to Result.

See this example:

struct Kids {}
struct Spouse {}
struct Cat {}
struct Family {
    let kids: Kids
    let spouse: Spouse
    let cat: Cat
}

struct KidsError: Error {}
struct SpouseError: Error {}
struct CatError: Error {}

enum FamilyError: Error {
    case kidsError(KidsError)
    case spouseError(SpouseError)
    case catError(CatError)
}

// With `throws`

func callKids() throws /* KidsError */ -> Kids { throw KidsError() }

func callSpouse() throws /* SpouseError */ -> Spouse { throw SpouseError() }

func callCat() throws /* CatError */ -> Cat { throw CatError() }

func callFamily() throws -> Family {
    let kids = try callKids()
    let spouse = try callSpouse()
    let cat = try callCat()
    return Family(kids: kids, spouse: spouse, cat: cat)
}

func callFamilySpecificError() throws /* FamilyError */ -> Family {
    do {
        let kids = try callKids()
        let spouse = try callSpouse()
        let cat = try callCat()
        return Family(kids: kids, spouse: spouse, cat: cat)
    } catch let error as KidsError {
        throw FamilyError.kidsError(error)
    } catch let error as SpouseError {
        throw FamilyError.spouseError(error)
    } catch let error as CatError {
        throw FamilyError.catError(error)
    }
}

// With `Result`

func callKidsResult() -> Result<Kids, KidsError> { Result.failure(KidsError()) }

func callSpouseResult() -> Result<Spouse, SpouseError> { Result.failure(SpouseError()) }

func callCatResult() -> Result<Cat, CatError> { Result.failure(CatError()) }

func callFamilyResult() -> Result<Family, FamilyError> {
    return callKidsResult()
        .mapError { error in FamilyError.kidsError(error) }
        .flatMap { kids in
            callSpouseResult()
                .mapError { error in FamilyError.spouseError(error)
            }.flatMap { spouse in
                callCatResult()
                    .mapError { error in FamilyError.catError(error) }
                    .map { cat in
                        Family(kids: kids, spouse: spouse, cat: cat)
                }
        }
    }
}
2 Likes