Swift - Implementing Equatable? - swift

I have the following class that I want to have Equatable. Everything works fine excep it seems like the operator completely overrides the global == operator.
// User.swift
class User: Equatable {
let id: Int
init(_ id: Int) {
self.id = id
}
}
func == (lhs: User, rhs: User) -> Bool {
return (lhs.id == rhs.id)
}
It seems like in other places in the code when I try to use == it complains that "T is not convertible to User". But this is a completely different class and has nothing to do with user
// ArrayExtension.swift
extension Array {
public func contains(object: T) -> Bool {
for x in self {
// Compile error here "T is not convertible to User"
if (x == object) {
return true
}
}
return false
}
}
What's wrong with the code

The problem is that the T in the Array is not necessarily Equatable. You cannot use == in your extension because of that.
The reason you get that error is that the compiler is trying its best to find a function that can be used called ==. It happens to be finding your == function but it gives an error because it doesn't actually match the types.
Note: The compiler could obviously use some usability work with its error messaging

Related

class AnyComparable inherits from class AnyEquatable

public class AnyEquatable: Equatable {
public let value: Any
private let equals: (Any) -> Bool
public init<E: Equatable>(_ value: E) {
self.value = value
self.equals = { $0 as? E == value }
}
public static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool {
lhs.equals(rhs.value) || rhs.equals(lhs.value)
}
}
public class AnyComparable: AnyEquatable, Comparable {
private let compares: (Any) -> Bool
public init<C: Comparable>(_ value: C) {
super.init(value)
self.compares = { ($0 as? C).map { $0 < value } ?? false }
}
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.compares(rhs.value) || rhs.compares(lhs.value)
}
}
I've got an error:
Overridden method 'init' has generic signature C where C:
Comparable which is incompatible with base method's generic signature
E where E: Equatable; expected generic signature to be C where C:
Equatable
Why does the compiler think that I'm overriding initializer? I didn't use the word "override". I can't override here because the method 'init' has different signature (which the compiler tells itself). It's not an overriding. I want the subclass to use its own initilizer, and I (obviously) don't want inherit superclass initializer.
So, how can I achieve that? What can be more natural than something comparable inherits from something equatable! Why can't I do that?
Note that your initialiser in the subclass does override the initialiser in the superclass. If you fix the constraint on C as the compiler asks you to, the next thing the compiler will tell you, is that you are missing an override keyword.
This behaviour is quite consistent, so it seems like it is deliberately designed that the generic constraints are not taken into account when determining whether one method overrides another. Here's another example of this:
class A {
func f<T>(t: T) {}
}
class B: A {
func f<C: Equatable>(t: C) {} // error
}
Anyway, one way you can work around this is to just change the argument label:
public init<C: Comparable>(comparable value: C) {
self.compares = { ($0 as? C).map { $0 < value } ?? false }
super.init(value)
}
The downside of this is that the client code gets a bit less concise. You have to do AnyComparable(comparable: something) every time, which is quite long. One solution is to put both AnyEquatable and AnyComparable in the same file, make both initialisers fileprivate. You can then provide factory functions (in the same file) that create these classes. For example:
public extension Equatable {
func toAnyEquatable() -> AnyEquatable {
.init(equatable: self)
}
}
public extension Comparable {
func toAnyComparable() -> AnyComparable {
.init(comparable: self)
}
}
Also note that your implementation of < doesn't make much sense. It should be:
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.compares(rhs.value) || (rhs != lhs && !rhs.compares(lhs.value))
}
and compares should mean "less than",
self.compares = { ($0 as? C).map { value < $0 } ?? false }
to say "lhs < rhs or rhs > lhs".
But even still, there are cases where using this class with completely unrelated types still doesn't make much sense, just FYI:
let a = AnyComparable(comparable: "foo")
let b = AnyComparable(comparable: 1)
print(a < b) // true
print(a > b) // true
print(a <= b) // false
print(a >= b) // false
print(a == b) // false
So please do be careful!

Returning an object that conforms to a generic constraint

I am trying to create a Builder for my ComplexObject:
import Foundation
class ComplexObject {
// lots of stuff
init<ObjectType, T>(_ closure: ((ObjectType) -> T)) {
// lots of init/setup code
}
// other initializers with generics, constructed
// by other Builders than ConcreteBuilder<O> below
}
protocol BuilderType {
associatedtype ObjectType
func title(_: String) -> Self
func build<T>(_ closure: ((ObjectType) -> T)) -> ComplexObject
}
struct Injected<O> {
//...
}
extension ComplexObject {
static func newBuilder<Builder: BuilderType, O>(someDependency: Injected<O>) -> Builder where Builder.ObjectType == O {
// vvvv
return ConcreteBuilder(someDependency: someDependency)
// ^^^^
// Cannot convert return expression of type 'ComplexObject.ConcreteBuilder<O>' to return type 'Builder'
}
struct ConcreteBuilder<O>: BuilderType {
private let dependency: Injected<O>
private var title: String
init(someDependency: Injected<O>) {
self.dependency = someDependency
}
func title(_ title: String) -> ConcreteBuilder<O> {
var builder = self
builder.title = title
return builder
}
func build<T>(_ closure: ((O) -> T)) -> ComplexObject {
return ComplexObject(closure)
}
}
}
but swiftc complains about the return ConcreteBuilder(...) line
Cannot convert return expression of type 'ComplexObject.ConcreteBuilder<O>' to return type 'Builder'
I also tried
static func newBuilder<Builder: BuilderType>(someDependency: Injected<Builder.ObjectType>) -> Builder {
return ConcreteBuilder(someDependency: someDependency)
}
with the same result. I see that I could just expose ConcreteBuilder, but I hoped to be able to hide that implementation detail. What am I missing here?
I'm not sure how to solve this issue, but the root of the problem is that newBuilder(someDependancy:) has a generic type signature, but it's really not generic.
Its return type asserts that function can return an object of any type T: BuilderType where Builder.ObjectType == O, but that's clearly not the case. Asking this function to return any type besides a ConcreteBuilder isn't supported. At best, you could use a force cast, but if someone writes let myBuilder: MyBuilder = ComplexObject.newBuilder(someDependancy: dec), the code would crash (even if MyBuilder satisfies your generic constraints) because you're trying to force cast ConcreteBuilder to MyBuilder.
As far as a solution... I don't have one. Fundamentally you just want to return BuilderType, but I don't think that's possible because it has an associated type.
Will this do ?
return ConcreteBuilder(someDependency: someDependency) as! Builder

Extend existing (generic) swift class to be hashable

I have some class that i want to put into a dictionary however that class is does not conform to Hashable i cant use it as a key in a Swift dictionary. Since its a class it can be identified by its location in memory and im happy to use that its identifier, the type itself doesnt fall into the value semantics world anyway.
Therefore i declare an extension to make it so
extension SomeGenericType : Hashable {
public var hashValue: Int {
return unsafeAddressOf(self).hashValue
}
}
This seems ok, however Hashable inherhits from Equatable so i need to implement tha too, my first try:
public func ==(lhs: SomeGenericType, rhs: SomeGenericType) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Errors with
"Reference to generic type 'SomeGenericType' requires arguments in <...>"
...fair enough so lets do that
public func ==<T : SomeGenericType >(lhs: T, rhs: T) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Now it says
"Reference to generic type 'SomeGenericType' requires arguments in <...>"
Hmm so i can make this work for all SomeGenericType's regardless of what type it gets. Maybe we can just put AnyObject in there?
public func ==<T : SomeGenericType<AnyObject>>(lhs: T, rhs: T) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
Ok now == is happy but apparantly im not implementing Hashable properly as there is now a error on my hashable extension saying:
"Type 'SomeGenericType<T>' does not conform to protocol 'Equatable'"
Ive tried fiddling with a constrained Extension on SomeGenericType but i cant seem to make a constrained extension of a type adopt another protocol, the language grammar doesnt seem to allow it, so Im in a bit of pickle here
Edit, for reference SomeGenericType is defined as follows:
class SomeGenericType<T> {
}
The correct syntax is
public func ==<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return unsafeAddressOf(lhs) == unsafeAddressOf(rhs)
}
The operands need to be instances of SomeGenericType for the
same type placeholder T.
For Swift 3, use ObjectIdentifier instead of unsafeAddressOf.
This is an older question but I recently run into a similar problem, except I had a struct.
You might want to implement 4 different infix operator functions:
// #1
public func ==<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return lhs === rhs // it's a class right - check the reference
}
// #2
public func !=<T>(lhs: SomeGenericType<T>, rhs: SomeGenericType<T>) -> Bool {
return !(lhs === rhs)
}
// #3
public func ==<T, U>(lhs: SomeGenericType<T>, rhs: SomeGenericType<U>) -> Bool {
return lhs.hashValue == rhs.hashValue
}
// #4
public func !=<T, U>(lhs: SomeGenericType<T>, rhs: SomeGenericType<U>) -> Bool {
return lhs.hashValue != rhs.hashValue
}
Problem solved? The program should use these and not the generic functions from the stdlib.
You could also check everything by it's hashValue. ;)

Error: Cannot find an overload for 'contains' that accepts an argument type in while loop

Why am I getting this error:
Cannot find an overload for 'contains' that accepts an argument type '[Vetex], Vertex'
if var child = extracted.child {
var visited = [Vertex]()
do {
child.parent = nil
child = child.next
visited.append(child)
} while contains(visited, child) == false
}
Your Vertex class should confirm to Equatable protocol.
// Class declaration
class Vertex : Equatable
{
}
func ==(lhs: Vertex, rhs: Vertex) -> Bool
{
// Implement your own logic here
return lhs.yourProperty == rhs.yourProperty
}
This is a good tutorial : Swift Comparison Protocols
That means that "contains" method doesn't accept [Vertex],vertex.
Can you post this method.It should look like this:
func contains (_: [Vertex],_:Vertex) -> Bool{
//your code
}

Swift compare two MetaTypes?

I need to test to see if a Type I'm passing to a function is of a certain class or not
func doSomething<T> (type: T.Type) -> T {
// Check to see if type is the same as Raw type?
if type == Raw.self { } // Doesn't work, Compile error
if type is? Raw.self { } // Doesn't work, Compile error
}
#objc class Raw {
}
Function overloading would be my first choice, but to answer the question; either use NSStringFromClass, or the following:
#objc class Raw {
}
func doSomething<T: AnyObject> (type: T.Type) -> T {
type as AnyClass === Raw.self as AnyClass { }
// return something
}
This solution seems to work with pure Swift classes too.