Oliver Pearmain
Oliver Pearmain

Reputation: 20590

Binary operator '===' cannot be applied to two 'String' operands

Why can't the === be used with String's in Swift? I am unable to compile the following:

let string1 = "Bob"
let string2 = "Fred"

if string1 === string2 {
    ...
}

and get the following error (on the if line):

Binary operator '===' cannot be applied to two 'String' operands


What I want to be able to do in my unit tests is, having performed a copyWithZone:, verify that two objects are indeed a different object with different pointers even if their values are the same. The following code doesn't work...

XCTAssertFalse(object1.someString === object2.someString)

If anyone knows of an alternative way please advise.

Upvotes: 6

Views: 3753

Answers (5)

nhgrif
nhgrif

Reputation: 62052

Swift's === operator, by default, is only defined for classes.

Swift's String type is not a class but a struct. It does not inherit from AnyObject and therefore cannot be compared by reference.

You could of course implement an === operator for String in Swift, but I'm not sure how it would be any different from the implementation of == for Swift's String type.

func ===(lhs: String, rhs: String) -> Bool {
    return lhs == rhs
}

Unless, of course, you really wanted to compare the references, I suppose you could do something like this:

func ===(lhs: String, rhs: String) -> Bool {
    return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}

However, for the sake of tests, rather than using the == or === operators, you should use the appropriate assertions:

XCTAssertEqual(foo, bar)
XCTAssertNotEqual(foo, bar)

Upvotes: 5

Eric Aya
Eric Aya

Reputation: 70097

Swift Strings are value type, not reference type, so there's no need for that, a copy will always be a different object.

You should just compare by value with ==.

Upvotes: 2

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

If you try really hard, you can force things to happen, but I'm not sure what that buys you.

class MyClass: NSObject, NSCopying {
    var someString: NSString = ""

    required override init() {
        super.init()
    }

    func copyWithZone(zone: NSZone) -> AnyObject {
        let copy = self.dynamicType.init()
        copy.someString = someString.copy() as? NSString ?? ""
        return copy
    }
}

let object1 = MyClass()
object1.someString = NSString(format: "%d", arc4random())
let object2 = object1.copy()

if object1.someString === object2.someString {
    print("identical")
} else {
    print("different")
}

prints identical, the system is really good at conserving strings.

Upvotes: 0

Marc Khadpe
Marc Khadpe

Reputation: 2002

The === operator is the identity operator. It checks if two variables or constants refer to the same instance of a class. Strings are not classes (they are structs) so the === operator does not apply to them.

If you want to check if two strings are the same, use the equality operator == instead.

Read all about the identity operator in the Swift documentation.

You can just check two objects for identity directly, instead of checking a property of type String.

 XCTAssertFalse(object1 === object2)

Upvotes: 3

gnasher729
gnasher729

Reputation: 52530

string1 and string2 are not NSString, but String. Since they are value objects, not reference objects, there is no reference that could be compared with ===.

Upvotes: 8

Related Questions