I’m a bit late here but
At most one type of specific error can be used with a
throws
.
Is this rule set in stone?
I understand that “sum types” are out of scope but, in my opinion, listing types is not a “sum type” but just, well, a list of types.
I would very much like to have a list of types thrown.
I think it would simplify many use cases, e.g. the family example would not have to be:
enum FamilyError : Error {
case kid(_ e: KidError)
case spouse(_ e: SpouseError)
case cat(_ e: CatError)
}
func callFamily() 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 CatError {
throw FamilyError.cat(error)
} catch let error as SpouseError {
throw FamilyError.spouse(error)
} catch let error as KidError{
throw FamilyError.kid(error)
}
}
but could be much simpler:
func callFamily() throws CatError, SpouseError, KidError -> Family {
let kids = try callKids()
let spouse = try callSpouse()
let cat = try callCat()
return Family(kids: kids, spouse: spouse, cat: cat)
}
I understand this just moves the catches to the call side. On the other hand, switching over FamilyError
is the same amount of code.
For Result
and rethrows
, the compiler could use the “natural sum type”: Search the inheritance tree until a type is found that all thrown types conform to (the search is guaranteed to end at Error
):
protocol ColoredError: Error { }
class BlueError: ColoredError { }
class DeepBlueError: BlueError { }
class RedError: ColoredError { }
func f() throws BlueError, DeepBlueError, RedError {}
is equal to
func f() -> Result<Void, ColoredError> {}