'Combining multiple Bool return values without shortcircuiting
Swift 2 has restrictions on using bitwise operators for Bool values. This is agreeable. In ObjC it was very useful to use it when you need to execute each operand. For example:
a.isFoo() & b.isFoo() & c.isFoo()
In this case, using the bitwise & will execute each method.
If I use the logical operator &&, it will execute the first one and if it is false, the expression will return false without executing the other two operands.
I want to find the same elegant way that & works, with Bool in Swift. Is it possible?
Solution 1:[1]
There is no such special operator but I would probably do it in this way:
if ![a.isBool(), b.isBool(), c.isBool()].contains(false) {
or just
let aCondition = a.isBool()
let bCondition = b.isBool()
let cCondition = c.isBool()
if aCondition && bCondition && cCondition {
but you can can also define your own operator to that.
Solution 2:[2]
You could mimic the same behaviour using a reduce operation on an array of your method calls, e.g.
/* example setup */
struct Foo {
let bar: Bool
init(_ bar: Bool) { self.bar = bar }
func isTrue() -> Bool { print("\(bar) foo!"); return bar }
}
let a = Foo(false)
let b = Foo(false)
let c = Foo(true)
/* naturally all three method calls will execute to construct the boolean
array, whereafter reduce will evaluate the combined conditional statement */
if [a.isTrue(), b.isTrue(), c.isTrue()].reduce(true, combine: { $0 && $1 }) {
print("Reached this ...")
} /* false foo!
false foo!
true foo! */
let d = Foo(true)
let e = Foo(true)
let f = Foo(true)
if [d.isTrue(), e.isTrue(), f.isTrue()].reduce(true, combine: { $0 && $1 }) {
print("Reached this ...")
} /* true foo!
true foo!
true foo!
Reached this ... */
or e.g. supplying your methods as variadic arguments to a function doing the method execution and combined conditional
func foo(calls: (() -> Bool)...) -> Bool {
return calls.map{ $0() }.reduce(true, combine: { $0 && $1})
}
let a = Foo(false)
let b = Foo(false)
let c = Foo(true)
if foo(a.isTrue, b.isTrue, c.isTrue) {
print("Reached this ...")
} /* false foo!
false foo!
true foo! */
let d = Foo(true)
let e = Foo(true)
let f = Foo(true)
if foo(d.isTrue, e.isTrue, f.isTrue) {
print("Reached this ...")
} /* true foo!
true foo!
true foo!
Reached this ... */
Solution 3:[3]
let values = [a.isFoo(), b.isFoo(), c.isFoo()]
let result = values.allSatisfy { $0 }
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Alexander |
| Solution 2 | |
| Solution 3 | Martin Mungai |
