Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend existing (generic) swift class to be hashable

Tags:

generics

swift

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

}
like image 949
Luke De Feo Avatar asked Oct 17 '15 16:10

Luke De Feo


People also ask

Can a class be hashable Swift?

The swift hashable create a class or struct with the “Hashable” keyword. The variable and its datatype are defines inside of swift class or struct. The swift hashable convert variable value into hash value.

What does it mean to be hashable Swift?

In Swift, a Hashable is a protocol that provides a hashValue to our object. The hashValue is used to compare two instances. To use the hashValue , we first have to conform (associate) the type (struct, class, etc) to Hashable property. For example, struct Employee: Hashable { ... }

Is string hashable in Swift?

Many types in the standard library conform to Hashable : Strings, integers, floating-point and Boolean values, and even sets are hashable by default.

Is Dictionary hashable in Swift?

Any type that conforms to the Hashable protocol can be used as a dictionary's Key type, including all of Swift's basic types. You can use your own custom types as dictionary keys by making them conform to the Hashable protocol.


1 Answers

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.

like image 63
Martin R Avatar answered Oct 15 '22 07:10

Martin R