Common Equatable class on Swift

938 views Asked by At

I need container for Any Equatable items in NOT Generic class (for example UI classes initial from storyboard). I need like this

var items: [Equatable]?

but it don't work, Equatable need Generic. the problem that there is no exist common Equatable class.


Ok - Go to generic! But if I do this

class Item<Value: Equatable>: Equatable {
   var value: Value
   init(_ value: Value) {
       self.value = value
   }
   //Equatable
   public static func ==(lhs: Item, rhs: Item) -> Bool {
       return (lhs.value == rhs.value)
   }
}

then I will be forced to specify the type in my nonGeneric-UI class. Like this

var items: [Item<WhatShouldBeHere?>]?

but again we come to the problem that there is no exist common Equatable class


Any solutions for container for All Equatable?

1

There are 1 answers

6
Alexander On BEST ANSWER

In lieu of existential types, you need to use a type eraser:

public struct 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 {
        return lhs.equals(rhs.value) || rhs.equals(lhs.value)
    }
}

example usage:

let items = [
    AnyEquatable(1),
    AnyEquatable(1.23),
    AnyEquatable(true),
    AnyEquatable("some string")
]

let desired = "some string"
let desiredAsAnyEquatable = AnyEquatable(desired)
let desiredDescription = String(reflecting: desired)

for item in items {
    let itemDescription = String(reflecting: item.value)
    let isEqualToDesired = item == desiredAsAnyEquatable
    print("\(itemDescription) is \(isEqualToDesired ? "": "not ")equal to \(desiredDescription)")
}

Example output:

1 is not equal to "some string"

1.23 is not equal to "some string"

true is not equal to "some string"

"some string" is equal to "some string"