'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