26

I'm trying to do an XOR operation in Swift 5. The documentation does not seem to mention explicitly doing it with two boolean values here:

https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html

Is this possible? It says to use the ^ operation but I get the error when trying:

 card != nil ^ appointment.instructor == nil

ERROR Adjacent operators are in non-associative precedence group 'ComparisonPrecedence'

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Zack117
  • 985
  • 1
  • 13
  • 28
  • 4
    `^` can't be applied to `Bool`. Use `!=` instead. What are you doing with the above statement? Throw in some `()` to keep it sane. You don't seem to be assigning it to a variable or testing it. – vacawama Apr 02 '19 at 15:32
  • Compare https://stackoverflow.com/questions/29555569/swift-1-2-xcode-6-3-removed-xor-operator-for-bool-value: The XOR operator for Bool was deprecated in Swift 1.2. – Martin R Apr 02 '19 at 17:01

3 Answers3

38

You need to define ^ for Bool since it only exists for Ints. See the apple documentation here.

Example:

import UIKit
import PlaygroundSupport

extension Bool {
    static func ^ (left: Bool, right: Bool) -> Bool {
        return left != right
    }
}

let a = true
let b = false
print (a^b)
Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • Here's a thought. In your main code just say left != right. So != is the XOR operator in swift, as in the answer below. – Sojourner9 Aug 04 '23 at 20:42
23

The ^ operator is defined for integer types but not for Bool. You could add your own definition, but it's not strictly needed. The XOR operation on Bool is the same as the != operation. Here's the truth tables for A XOR B and A != B:

A B A^B A!=B
F F  F   F
F T  T   T
T F  T   T
T T  F   F

So we could write your expression like this:

(card != nil) != (appointment.instructor == nil)

That is kind of hard to understand though. If the goal is to ensure that exactly one of the cases is true, I might write it like this for clarity:

[(card != nil), (appointment.instructor == nil)].filter({ $0 == true }).count == 1
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
9

The documentation clearly states that ^ is the bitwise XOR operator and since a Bool is only a single bit, bitwise XOR is not defined on it. If you put correct parentheses on your expression, you get the correct error message:

(card != nil) ^ (appointment.instructor == nil)

Binary operator '^' cannot be applied to two 'Bool' operands

There's no XOR operator in Swift, so to do a XOR on two Bools, you need to define your own XOR function or operator.

infix operator ^^
extension Bool {
    static func ^^(lhs:Bool, rhs:Bool) -> Bool {
        if (lhs && !rhs) || (!lhs && rhs) {
            return true
        }
        return false
    }
}

Tests:

let trueValue:Bool? = true
let falseValue:Bool? = false
let nilValue:Bool? = nil

(trueValue != nil) ^^ (nilValue != nil) // true
(trueValue != nil) ^^ (falseValue != nil) // false
(nilValue != nil) ^^ (nilValue != nil) // false
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116