Reputation: 2540
import Foundation
struct NotEquable {}
struct Box<T> {
let id: Int
let value: T
}
extension Box: Equatable {
static func ==<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id
}
static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
}
infix operator ====: AdditionPrecedence
public protocol OperatorEqual {
static func ====(lhs: Self, rhs: Self) -> Bool
}
extension Box: OperatorEqual {
static func ====<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id
}
static func ====<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
}
public protocol MethodStyleEquatable {
static func equal(lhs: Self, rhs: Self) -> Bool
}
extension Box: MethodStyleEquatable {
static func equal<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id
}
static func equal<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
}
func freeEqual<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id
}
func freeEqual<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
let a = Box(id: 1, value: 1)
let b = Box(id: 1, value: 2)
a == b
a ==== b
freeEqual(lhs: a, rhs: b)
Box<Int>.equal(lhs: a, rhs: b)
let c = Box(id: 1, value: NotEquable())
let d = Box(id: 1, value: NotEquable())
c == d
c ==== d
freeEqual(lhs: c, rhs: d)
Box<NotEquable>.equal(lhs: c, rhs: d)
In the above snippet, there are 4 implementation of Equatable
: the default implementation, the custom operator style, the method style and the free function style. I found that using the operator style in default or custom case always call the generic version of the equal function. On the other hand, using method or free function style will call correct version according to T
conform to Equatable
or not. Its this a bug or how can I make generic struct conforms to Equatable
correctly.
Upvotes: 3
Views: 1270
Reputation: 93181
You are confusing generic parameter to the class to that of the equality function. As written, your code is equivalent to this:
struct Box<T1> {
let id: Int
let value: T1
}
extension Box: Equatable {
static func ==<T2>(lhs: Box<T2>, rhs: Box<T2>) -> Bool {
return lhs.id == rhs.id
}
static func ==<T3: Equatable>(lhs: Box<T3>, rhs: Box<T3>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
}
Change your definition to this:
extension Box : Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id
}
}
extension Box where T: Equatable {
static func ==(lhs: Box<T>, rhs: Box<T>) -> Bool {
return lhs.id == rhs.id && lhs.value == rhs.value
}
}
And it works as expected.
Upvotes: 5