Swift 2 Generic data structure not conforming to Equatable protocol - swift

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!

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

Related

how to make protocol to conform another protocol in Swift?

I make a extension for Array where Elements are Object, so I can compare them by their address.
public extension Array where Element: AnyObject {
func hasExactSameItem(_ searchingItem: Element) -> Bool {
guard let _ = indexOfExactSameItem(searchingItem) else { return false }
return true
}
func indexOfExactSameItem(_ searchingItem: Element) -> Int? {
for (index, item) in self.enumerated() {
if searchingItem === item {
return index
}
}
return nil
}
}
There is another protocol conforming AnyObject protocol
public protocol IMServerListener: AnyObject {
}
I have a array containing IMServerListener
private var listeners = [IMServerListener]()
When I start adding listener to that array, the compiler complaining that '[IMServerListener]' requires that 'IMServerListener' conform to 'AnyObject'
func addListener(_ listener: IMServerListener) {
listeners.hasExactSameItem(listener)
}
I thought the IMServerListener is conforming the AnyObject protocol, so why did it happened?
I tried to construct a similar example in a playground:
import UIKit
protocol Foo: AnyObject {
func foo()
}
protocol Bar: Foo {}
class A: Bar {
func foo() {}
}
var bars = [Bar]()
bars.append(A())
bars.append(A())
bars[0] === bars[1] // equals operator used from AnyObject
Observations:
(1) Protocols can inherit from each other. If I leave out the implementation of foo() in class A it leads to a compiler error.
(2) Class A does inherit from AnyObject through Bar and Foo otherwise I could not use the equals operator.
To your question:
compiler complaining that '[compiler complaining that '[IMServerListener]' requires that 'IMServerListener' conform to 'AnyObject']' requires that 'IMServerListener' conform to 'AnyObject' sounds like there might be something wrong with the implementation of IMServerListener itself.
I am happy to extend my answer if you can show us this implementation / more code in general.
Cheers,
Dominic

Conformance to a protocol (as a protocol)

Say I have a protocol Item, and a struct ConcreteItem that conforms to it.
protocol Item {
var name: String { get }
}
struct ConcreteItem: Item {
let name: String
}
At some point I want to have two sets of ConcreteItem.
let set1 = Set([ConcreteItem(name: "item1")])
let set2 = Set([ConcreteItem(name: "item2"), ConcreteItem(name: "item1")])
Which I'd expect to return the item with name "item1".
I can make ConcreteItem conform to Hashable and the Set code will work. However, lets say I also had the following:
struct AnotherConcreteItem: Item {
let name: String
}
I'd like AnotherConcreteItem to also conform to Hashable simply for having conformed to Item.
However, when I try to implement that idea:
extension Item: Hashable {
var hashValue: Int {
return name.characters.count
}
}
I get the following error: Extension of protocol 'Item' cannot have an inheritance clause.
Extension of protocol 'Item' cannot have an inheritance clause
Here item is the protocol so conforming Hashable protocol will not work. For more details Refer here
What you are trying to do is possible with some protocols, but not all. If the protocol you are trying to conform to does not have any associated types or Self, this is possible.
Example:
protocol A {
func foo()
}
protocol Item: A {
var name: String { get }
}
struct ConcreteItem: Item {
let name: String
}
extension Item {
func foo() {
}
}
Everything that conforms to Item will also conform to A.
However, Hashable has Self constraints. To conform to Hashable, you must also conform to Equatable. To conform to Equatable, the implementation of == must be in a concrete class, not another protocol because Equatable can't be used as a parameter type. The most you can do is something like this:
protocol Item: Hashable {
var name: String { get }
}
struct ConcreteItem: Item {
let name: String
// you need to implement == in every concrete class
static func ==(lhs: ConcreteItem, rhs: ConcreteItem) -> Bool {
return ...
}
}
extension Item {
var hashValue: Int {
return name.characters.count
}
}

How to use a Set in Swift 3.0 without generic usage

First of all i have to say i come from Java programming and compared with Java everything in Swift 3.0 seems to be totally complicated. I thought what i want to do is easy but it turned out it is not.
I have two objects:
protocol Customer {
}
and:
class Consulter {
}
I want my Consulter class to hold a Set of Customer:
class Consulter {
var customers: Set<Customer>;
}
Ok here the first thing. The Compiler now is complaining that Customer has to implement Hashable... really? Swift isnt doing that for me? Ok. So lets go for it:
func ==(lhs: Customer, rhs: Customer) -> Bool {
return lhs.hashValue == rhs.hashValue;
}
protocol Customer: Hashable {
var: hashValue: Int {
return "123".hashValue;
}
}
And in my Consulter class i now would have to do the following:
class Consulter<T: Customer> {
var customers: Set<T>;
}
Ok this is working. But now i have another class:
func ==(lhs: Location, rhs: Location) -> Bool { // here the error!
return lhs.hashValue == rhs.hashValue;
}
class Location<T: Customer> : Hashable {
var customer: T;
....
}
For the Equatable of the class Location i now get the error:
Reference to generic type 'Location' requires arguments in <...>
So what argument is the compiler expecting here? I dont know any concrete types at this point.
EDIT
my Customer protocol will later have different concrete implementations. A Customer can for example be a Family or a Person. In the Consulter class i want to have a Set of Customer containing both: families and persons. I think this is a simple and logical approach.
Since you intend to use types conforming to Customer in applications where they must be Hashable (e.g. as members of a Set), there is no reason why not to add this Hashable constraint directly to the Customer protocol. This way you move the responsibility to conformance to Hashable to the actual types that you consider to be Customer's
protocol Customer: Hashable {}
class Consulter<T: Customer> {
var customers: Set<T>?
}
class Location<T: Customer>: Hashable {
var customer: T
init(customer: T) { self.customer = customer }
var hashValue: Int {
return customer.hashValue
}
}
func ==<T: Customer>(lhs: Location<T>, rhs: Location<T>) -> Bool {
return lhs.customer == rhs.customer /* && ... test other properties */
}
Also, be careful using X.hashValue == Y.hashValue for testing for equality, since there is no guarantee that hashvalues are unique (consider them mainly used for clever "bin" categorization).
Or, since Swift 3
// ... as above
class Location<T: Customer>: Hashable {
var customer: T
init(customer: T) { self.customer = customer }
var hashValue: Int {
return customer.hashValue
}
static func ==(lhs: Location<T>, rhs: Location<T>) -> Bool {
return lhs.customer == rhs.customer /* && ... test other properties */
}
}

Make Swift protocol conform to Equatable on associated type

In Swift 2.1 (running XCode 7.2), I am trying to have a Protocol with associated type conform to Equatable.
// (#1)
/**
A Node in a graph
*/
public protocol GraphNode : Equatable {
typealias Content : Equatable
/**
The content of the node.
E.g. in a graph of strings, this is a string
*/
var content: Content {get}
/// The list of neighbours of this Node in the graph
var children: [Self] {get}
}
As we could have non-homogeneous implementations of the protocol that define a different type for the associated type, I expect that I won't be able to define here (at the protocol level, not at the implementation level) an equality function:
// (#2)
/// Won't compile, as expected
public func ==(lhs: GraphNode, rhs: GraphNode) {
return lhs.content == rhs.content
}
This is because I have no guarantee that lhs.Content is the same type as rhs.Content.
However I was hoping I could specify it with some generic constraint, such as:
// (#3)
/// Won't compile, why?
public func ==<Node1 : GraphNode, Node2 : GraphNode where Node1.Content == Node2.Content>(lhs: Node1, rhs: Node2)
{
return lhs.content == rhs.content // ERROR: Binary operator '==' cannot be applied to two 'Node1.Content' operands
}
In #3, we know that both lhs and rhs have the same type, and we know (from the specification of the associated type as Equatable) that Content is equatable. So why can't I compare them?
Add -> Bool. Just a bad error message. Sometimes writing function declaration across multiple lines doesn't make it more readable.
public func ==<Node1 : GraphNode, Node2 : GraphNode where Node1.Content == Node2.Content>(lhs: Node1, rhs: Node2) -> Bool {
return (lhs.content == rhs.content)
}

Swift protocol forcing the Equatable protocol

I have define 2 protocols.
I need the first one (NameProtocol) to enforce the Equatable protocol.
While the other class (BuilderProtocol) have a method that return the first one (NameProtocol).
public protocol NameProtocol : Equatable {
var name: String { get }
}
public protocol BuilderProtocol {
func build() -> NameProtocol? // Compiler error
init()
}
The compiler error :
"Protocol 'NameProtocol' can only be used as a generic constraint because it has Self or associated type requirements"
I need the object return by build() to return an object conforming to the NameProtocol and on which I can define ==
Is there a way I can make this work?
Thanks
If using a typealias in BuilderProtocol how can I make the array declaration work?
public protocol OtherRelatedProtocol {
var allNames : Array<NameProtocol> { get }
}
Conclusion
I will remove the Equatable and implement an isEqual method.
public protocol NameProtocol {
func isEqual(nameable: NameProtocol) -> Bool
var name: String { get }
}
If you're familiar with Java or C#, Swift protocols are about halfway between generics and interfaces. One thing that you can do in a protocol, for instance, is this:
protocol Foo {
func compareWith(foo: Self)
}
Classes that implement this protocol will have a method compareWith that accept an object of their own type (and not an object of type Foo).
This is what the compiler calls "Self or associated type requirements", and this is how Equatable is defined (it needs an operator== that accepts two Self operands). The downside of these protocols, though, is that you can only use them as generic constrains: you can't use them as an expression type.
The solution is to use generics. In this case, you'd make your ProtocolBuilder protocol generic, with a constraint that the type implements NameProtocol.
public protocol NameProtocol : Equatable {
var name: String { get }
}
public protocol BuilderProtocol {
typealias T: NameProtocol
func build() -> T?
init()
}