5

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> {

}
Luke De Feo
  • 2,025
  • 3
  • 22
  • 40
  • Ive eddited to show how SomeGenericType is implemented, the original version works when the type im extending is not generic – Luke De Feo Oct 17 '15 at 16:58

2 Answers2

6

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
0

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. ;)

DevAndArtist
  • 4,971
  • 1
  • 23
  • 48