Overloading == operator calls parent function for != - swift

I overloaded the == operator on a class. Then a child class also overloads the == operator. My understanding is that both == and != are supposed to call the same == function. However, when running tests, == calls the function on the child class, yet != calls the function on the parent class. This is bizarre. I would expect the same behavior for both == and !=.
class Description: Equatable {
var id : Int = IdFactory.id()
static func == (lhs: Description, rhs: Description) -> Bool {
assertionFailure("Child Description must override == method.")
return false
}
}
class LineDescription : Description {
var track = 0
static func == (lhs: LineDescription, rhs: LineDescription) -> Bool {
if lhs.track != rhs.track { return false }
return true
}
}
import XCTest
class LineDescriptionTest: XCTestCase {
func testEquality(){
let ld = LineDescription()
ld.track = 9
let ld2 = LineDescription()
ld2.track = 9
XCTAssert(ld == ld2) //<--Calls child == function
ld2.track = 1
XCTAssert(ld != ld2) //<--Calls parent != function
}
}

Related

How to simplify this Swift code with closures

I'm trying to create a Set game, where 3 cards make a Set only when each of their attributes is the same, or is different.
import Foundation
struct Card {
var shape: Variant
var numberOfShapes: Variant
var shading: Variant
var color: Variant
enum Variant: Int {
case one = 1
case two
case three
static var all: [Variant] { return [.one, .two, .three] }
}
}
extension Card {
static func isSet(cards: [Card]) -> Bool {
if cards.count == 3 {
var shapeMakesSet: Bool {
if cards[0].shape.rawValue == cards[1].shape.rawValue && cards[0].shape.rawValue == cards[2].shape.rawValue {
return true
} else if cards[0].shape.rawValue != cards[1].shape.rawValue && cards[0].shape.rawValue != cards[2].shape.rawValue && cards[1].shape.rawValue != cards[2].shape.rawValue {
return true
} else {
return false
}
}
}
}
}
I was thinking of creating 4 Bool variables for each attribute inside isSet but this doesn't seem to be a good idea. It would probably work, but would take lots of lines. Is there any way I can simplify it using closures or something else?

A set is not equal but an array from this set is equal?

I work with unit-tests and encounter this problem:
I have some classes and each have their own isEqual() method. At some point I came to a situation where an unit-test sometimes fails and sometimes succeeds.
I check the equality of two objects that contain a set of objects. Here the the problem arises. Sometimes the test "obj1.mySet == obj2.mySet" fails - sometimes not. I test this with only one object in each set (mySet). The test for the equality of this objects (in mySet) itself succeeds.
I tried some hours to find a mistake in my code, but couldn't find any. Now I have a workaround that helps to pass the test, but I do not understand, what's going on. I have a method within the test-objects, that returns the objects of the set as an (ordered) array. When I test the equality of this arrays, the test always succeeds.
Do someone know, what’s going on?
Update:
In my BaseClass
func hash(into hasher: inout Hasher) { hasher.combine(firebaseID) }
static func == (lhs: FirebaseObject, rhs: FirebaseObject) -> Bool { return lhs.isEqual(to: rhs) }
func isEqual(to object: Any?) -> Bool {
guard object != nil && object is FirebaseObject else { return false }
let value = object as! FirebaseObject
return firebaseID == value.firebaseID && name == value.name
}
In the SubClass
override func isEqual(to object: Any?) -> Bool {
guard object != nil && object! is MealPlanned else { return false }
let obj = object as! MealPlanned
var result = ""
if !super.isEqual(to:obj) { result.append("fbObject ") }
if portions != obj.portions { result.append("portions ") }
if imgID != obj.imgID { result.append("imgID ") }
if meal != obj.meal { result.append("meal ") }
if date != obj.date { result.append("date ") }
if portionsInBaseMeal != obj.portionsInBaseMeal {result.append("portionsInBaseMeal ") }
if getIngrediencesInMeals() != obj.getIngrediencesInMeals() { result.append("ingrediencesInMeals ") }
if result.count > 0 {
if (showsDifference) { print("difference in MealPlanned <\(obj.name ?? "Fehler")>: \(result)") }
return false
}
return true
}
I did it this way, to find and print the problem.
This version succeeds.
if getIngrediencesInMeals() != obj.getIngrediencesInMeals() { result.append("ingrediencesInMeals ")
getIngrediencesInMeals() returns the set as an ordered array.
In this way the test sometimes succeeds sometimes fails:
if ingrediences != ingrediences { result.append("ingrediencesInMeals ")
This returns the ordered array:
func getIngrediencesInMeals() -> [IngredienceInMeals] { return ingrediences.sorted{ $0.position < $1.position } }
in IngredienceInMeals
override func isEqual(to object: Any?) -> Bool {
guard object != nil && object! is IngredienceInMeals else { return false }
let obj = object as! IngredienceInMeals
var result = ""
if !super.isEqual(to:obj) { result.append("fbObject ")}
if unit != obj.unit { result.append("unit ")}
if quantity != obj.quantity { result.append("quantity ")}
if ingredience != obj.ingredience { result.append("ingredience ")}
if position != obj.position { result.append("position ")}
if result.count > 0 {
if (showsDifference) { print("difference in IngredienceInMeal <\(obj.name ?? "Fehler")>: \(result)") }
return false
}
return true
}
if you want to compare two objects use Equatable protocol method in your object class
example of compare two objects
class ItemModel : Equatable {
var TypeOfOffer : String?
var TypeOfSelling : String?
var Address : String?
var NumberOfRoom : String?
var Price : String?
var Image : String?
var ID : String?
var itemId : String?
init(TypeOfOffer : String? , TypeOfSelling : String?, Address : String?, NumberOfRoom : String? , Price : String?, Image : String?, ID : String?, itemId : String? )
{
self.TypeOfOffer = TypeOfOffer
self.TypeOfSelling = TypeOfSelling
self.Address = Address
self.NumberOfRoom = NumberOfRoom
self.Price = Price
self.Image = Image
self.ID = ID
self.itemId = itemId
}
static func == (lhs: ItemModel, rhs: ItemModel) -> Bool {
var isIt = true
isIt = (lhs.TypeOfOffer == "" || lhs.TypeOfOffer == rhs.TypeOfOffer)
&& (lhs.TypeOfSelling == "" || lhs.TypeOfSelling == rhs.TypeOfSelling)
&& (lhs.Address == "" || lhs.Address == rhs.Address)
&& (lhs.NumberOfRoom == "" || lhs.NumberOfRoom == rhs.NumberOfRoom)
&& (lhs.Price == "" || lhs.Price == rhs.Price)
return isIt
}
}
Compare two instances of an object in Swift!

How to update NSResponder selector in swift 2.2

I am implementing a NSControlTextEditingDelegate protocol and I don't know which class/protocol i should match with e.g. commandSelector. #selector(WhichClass.moveUp(_:)) so that the equality will pass.
Currently everything is ok with swift 2.1:
func control(control: NSControl, textView: NSTextView, doCommandBySelector commandSelector: Selector) -> Bool {
var goUp = false
var goDown = false
if (commandSelector == Selector("moveUp:") ||
commandSelector == Selector("moveBackward:") ||
commandSelector == Selector("moveUpAndModifySelection:") ||
commandSelector == Selector("moveParagraphBackwardAndModifySelection:")
)
{
goUp = true
}
if (commandSelector == Selector("moveDown:") ||
commandSelector == Selector("moveForward:") ||
commandSelector == Selector("moveDownAndModifySelection:") ||
commandSelector == Selector("moveParagraphForwardAndModifySelection:")
) {
goDown = true
}
//...
}
Try this:
if (commandSelector == #selector(NSResponder.moveUp) ||
You can write it as the following if you prefer:
if (commandSelector == #selector(NSResponder.moveUp(_:)) ||
In fact, generated Selector instance from #selector does not contain the class info. So, you just find any class defining the same method with the same signature.
And if you cannot find any class, you can define it in your own protocol and use the protocol name.
#objc protocol MyProtocol {
func moveUp(_:AnyObject)
//...
}
And use it in #selector:
if (commandSelector == #selector(MyProtocol.moveUp(_:)) ||
The latter should be the last way, but it actually works.

Hashing problems using a wrapper class around NSUUID as the key

** REWRITE **
OK, it turns out I'm really asking a different question. I understand about hashValue and ==, so that's not relevant.
I would like my wrapper class BUUID to "do the right thing" and act just like NSUUID's act in a Dictionary.
See below, where they don't.
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
Results. Note that I can look up using NSUUID nB and get back what I put under nA. Not so with my BUUID.
a: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
b: 9DE6FE91-D4B5-4A6B-B912-5AAF34DB41C8
a === b: false
a == b: true
Optional("Hi") nil
nA: <__NSConcreteUUID 0x7fa193c39500> BB9F9851-93CF-4263-B98A-5015810E4286
nB: <__NSConcreteUUID 0x7fa193c37dd0> BB9F9851-93CF-4263-B98A-5015810E4286
nA === nB: false
nA == nB: true
Optional("Hi") Optional("Hi")
Inheriting from NSObject also assumes isEqual(object: AnyObject?) -> Bool method overloading:
import Foundation
class BUUID: NSObject {
init?(str: String) {
if let uuid = NSUUID(UUIDString: str) {
_realUUID = uuid
}
else {
return nil
}
}
override init() {
_realUUID = NSUUID()
}
private var _realUUID: NSUUID
override func isEqual(object: AnyObject?) -> Bool {
guard let buuid = object as? BUUID else {
return false
}
return buuid._realUUID == _realUUID
}
override var description: String { get { return _realUUID.UUIDString } }
override var hashValue: Int { get { return _realUUID.hashValue } }
var UUIDString: String { get { print("WARNING Use description or .str instead"); return _realUUID.UUIDString } }
var str: String { get { return _realUUID.UUIDString } }
}
func ==(lhs: BUUID, rhs: BUUID) -> Bool { return lhs._realUUID == rhs._realUUID }
let a = BUUID()
let b = BUUID(str: a.str)!
print("a: \(a)\nb: \(b)")
print("a === b: \(a === b)")
print("a == b: \(a == b)")
var d = [a: "Hi"]
print("\(d[a]) \(d[b])")
let nA = NSUUID()
let nB = NSUUID(UUIDString: nA.UUIDString)!
print("na: \(nA)\nnB: \(nB)")
print("nA === nB: \(nA === nB)")
print("nA == nB: \(nA == nB)")
var nD = [nA: "Hi"]
print("\(nD[nA]) \(nD[nB])")
So the answer is to not make BUUID inherit from NSObject, which undercuts the Swiftiness of overriding ==.
So:
extension BUUID: Hashable {}
class BUUID: CustomStringConvertible {
// take away all 'override' keywords, nothing to override
// otherwise same as above
}
Interesting!
This answer is relevant to initially asked question: Why that's possible to get two key-value pairs with identical key's hashes in a dictionary
This example illustrates that keys in Dictionary can have identical hashes, but equality operation should return false for different keys:
func ==(lhs: FooKey, rhs: FooKey) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
class FooKey: Hashable, Equatable {
var hashValue: Int {
get {
return 123
}
}
}
var d = Dictionary<FooKey, String>()
let key1 = FooKey()
let key2 = FooKey()
d[key1] = "value1"
d[key2] = "value2"
Output
[FooKey: "value1", FooKey: "value2"]
That's definitely not good to have all keys with the same hash. In this case we are getting that worst case when search element complexity fells down to O(n) (exhaustive search). But it will work.

Defining `Comparable` for optional types in Swift 1.2

import SwiftyJSON
public typealias FeedItem = JSON
extension FeedItem {
var id: Int { get { return self["id"].intValue } }
}
public func <(lhs: FeedItem, rhs: FeedItem) -> Bool {
return lhs.id < rhs.id
}
public func ==(lhs: FeedItem, rhs: FeedItem) -> Bool {
return lhs.id == rhs.id
}
extension FeedItem:Comparable {}
extension Optional : Comparable {}
public func < <T>(l:T?, r:T?) -> Bool {
if let a=l,b=r {
return a < b
} else if (l==nil) && (r != nil) { return true }
else { return false }
}
public func == <T>(l:T?, r:T?) -> Bool {
if let a=l, b=r {
return a==b
} else {
return false
}
}
First, it should read extension Optional<T where T:Comparable>: Comparable but swift 1.2 does not allow that. Anyway I can express the constraint more explicitly rather than expecting the reader to realize the fact by noticing return a < b and return a==b ?
Second (and apparently more important): the code above works when I use < and > but minElement and maxElement both return nil when a nil is present in their input no matter what and min and max fall into infinite recursion:
let items: [FeedItem?] = [ nil, .Some(JSON(["id":2])), .Some(JSON(["id":1])) ]
println(items[0]?.id) // nil
println(items[1]?.id) // Optional(2)
println(items[2]?.id) // Optional(1)
println(items[0] < items[1]) // true
println(items[1] < items[2]) // false
println(items[2] < items[1]) // true
println(minElement(items)) // nil
println(maxElement(items)) // nil
println( min(items[0],items[2]) ) // nil
println( min(items[2],items[1]) ) // crashes due to infinite recursion
I'm no debug (or swift) expert but from what I can gather in XCode I believe the
if let a=l,b=r {
return a < b
}
part somehow misses the point that a and b are not Optionals but FeedItems. I expect the a < b should call the < operator on FeedItem and not the one on Optional but apparently this is exactly what happens; i.e. a < b resolves to the same function it is called from (that is, the < for Optionals) and thus a recursion happens. I might be wrong though.
Insights ?