Bool has 2 values:
Bool? has 3 values, .none (a.k.a. nil), and one .some case wrapping each of the 2 possible cases of Bool:
.some(true)
.some(false)
.none
Bool?? has 4 values, .none, and one .some case wrapping each of the 3 possible cases of Bool?:
.some(.some(true))
.some(.some(false))
.some(.none)
.none
To make a first approximation of a solution, we can enumerate all possible values:
func getLhs() throws -> Bool? { return nil }
func getRhs() throws -> Bool? { return nil }
func f() -> Bool? {
let lhs: Bool?? = try? getLhs()
let rhs: Bool?? = try? getRhs()
switch (lhs, rhs) {
case (.some(.some(true)), .some(.some(true))): return true
case (.some(.some(true)), .some(.some(false))): return true
case (.some(.some(true)), .some(.none)): return true
case (.some(.some(true)), .none): return true
case (.some(.some(false)), .some(.some(true))): return true // result of OR
case (.some(.some(false)), .some(.some(false))): return false
case (.some(.some(false)), .some(.none)): return false
case (.some(.some(false)), .none): return false
case (.some(.none), .some(.some(true))): return true
case (.some(.none), .some(.some(false))): return false
case (.some(.none), .some(.none)): return nil
case (.some(.none), .none): return nil
case (.none, .some(.some(true))): return true
case (.none, .some(.some(false))): return false
case (.none, .some(.none)): return nil
case (.none, .none): return nil
}
}
So now this is obviously crazy, but we can collapse cases by binding variables:
switch (lhs, rhs) {
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.none)): return l
case let (.some(.some(l)), .none): return l
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.none)): return l
case let (.some(.some(l)), .none): return l
case let (.some(.none), .some(.some(r))): return r
case let (.some(.none), .some(.some(r))): return r
case (.some(.none), .some(.none)): return nil
case (.some(.none), .none): return nil
case let (.none, .some(.some(r))): return r
case let (.none, .some(.some(r))): return r
case (.none, .some(.none)): return nil
case (.none, .none): return nil
}
And we can remove the duplicate cases:
switch (lhs, rhs) {
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.none)): return l
case let (.some(.some(l)), .none): return l
case let (.some(.none), .some(.some(r))): return r
case (.some(.none), .some(.none)): return nil
case (.some(.none), .none): return nil
case let (.none, .some(.some(r))): return r
case (.none, .some(.none)): return nil
case (.none, .none): return nil
}
We can then group all the nested nil cases:
switch (lhs, rhs) {
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.none)): return l
case let (.some(.some(l)), .none): return l
case let (.some(.none), .some(.some(r))): return r
case let (.none, .some(.some(r))): return r
case (.some(.none), .some(.none)),
(.some(.none), .none),
(.none, .some(.none)),
(.none, .none):
return nil
}
We can then just catch all those in a default:
switch (lhs, rhs) {
case let (.some(.some(l)), .some(.some(r))): return l || r
case let (.some(.some(l)), .some(.none)): return l
case let (.some(.some(l)), .none): return l
case let (.some(.none), .some(.some(r))): return r
case let (.none, .some(.some(r))): return r
default: return nil
}
But this whole thing is crazy
Why do you have a function that throws AND returns an Optional? It would be much better to make the function return a non optional bool, and have the nil cases handled by one of the exceptions. Alternatively, you could return a Result<Bool, Error>, where one of the error cases encoded the nil.
If you had to stick with these types, a switch is the wrong way to go about it entirely. You could use Optional.map or Optional.flatMap, but those would get hairy too.
try?withtryin ado/catch.catchis for. Simplyreturn nilin thecatch.?? nildoesn't do anything.getLhsandgetRhslook like or where this code lives or what we are supposed to return.