Alex Ackerman Alex Ackerman - 2 months ago 16
Swift Question

Swift 2 Generic data structure not conforming to Equatable protocol

I am working on building a flexible data structure in Swift called Node that, by itself, is not tied to any type of content. However, the Payload data within the Node is declared as the following generic Element struct that conforms to the Equatable protocol:

public struct Element<T>: Equatable {
var data: T;
}

public func ==<T:Equatable>(lhs: Element<T>, rhs: Element<T>) -> Bool {
return lhs.data == rhs.data;
}


The constraint is that the Element has to be tied to an equatable class type. The problem I'm having is with the Node containing this Element. The Node would be used in a Dictionary, Array, or any other container type. Here is what I have:

public class Node: Equatable {

var payload: Element<AnyObject>

init(_data: Element<AnyObject>) {
self.payload = _data
}

}

public func ==(lhs: Node, rhs: Node) -> Bool {
return lhs.payload == rhs.payload;
}


Of course, I'm getting the error that AnyObject does not conform to Equatable. Is there any way to constrain the declaration of the payload to only Objects that are equatable? At this point, I don't know what kind of objects may be stored in the payload.

Also just realized I need to put a class check in the == function in Node to make sure the two Node payloads are compatible to be compared--don't need them to be.

Thoughts? Thank you!

Answer

In order to constrain payload to a type that is Equatable, you'll need Node to be a generic class so that it can pass along that constraint.

You can specify the constraint in your class declaration:

public class Node<T: Equatable>: Equatable {...}

And then when declaring your payload you can set its Element type to just T:

var payload: Element<T>

When testing the code, I had to also make the generic constraint, T, in Element conform to Equatable. Entire code for reference:

public struct Element<T: Equatable>: Equatable {
    var data: T
}

public func ==<T:Equatable>(lhs: Element<T>, rhs: Element<T>) -> Bool {
    return lhs.data == rhs.data
}

public class Node<T: Equatable>: Equatable {
    var payload: Element<T>
    init(_data: Element<T>) {
        self.payload = _data
    }
}

public func ==<T: Equatable>(lhs: Node<T>, rhs: Node<T>) -> Bool {
    return lhs.payload == rhs.payload
}

This will produce the following results:

Node(_data: Element(data: 1)) == Node(_data: Element(data: 1)) // true
Node(_data: Element(data: 1)) == Node(_data: Element(data: 2)) // false
Comments