Swift set equatable sometimes true sometimes false - swift

I have a struct conforming to Hashable. This model is put in a Set. Randomly when I check if the set contains the model it returns true/false. Why is this?
enum Feature: String {
case a
case b
}
struct FeatureState: Hashable {
let feature: Feature
let isEnabled: Bool
}
extension FeatureState: Equatable {
static func == (lhs: FeatureState, rhs: FeatureState) -> Bool {
lhs.feature == rhs.feature
}
}
let fs1 = FeatureState(feature: .a, isEnabled: false)
let fs2 = FeatureState(feature: .a, isEnabled: true)
featureStates.insert(fs1)
print(featureStates.contains(fs2)) // sometimes true, sometimes false

Set.contains uses hashes to check whether an element is already part of the Set or not and only uses the == operator if the hash values of two elements are the same. Because of this, you need to provide your own hash(into:) implementation to make the hash value only dependant on feature, but not isEnabled.
struct FeatureState {
let feature: Feature
let isEnabled: Bool
}
extension FeatureState: Hashable {
static func == (lhs: FeatureState, rhs: FeatureState) -> Bool {
lhs.feature == rhs.feature
}
func hash(into hasher: inout Hasher) {
hasher.combine(feature)
}
}

Related

Avoid the usage of a switch statement when parsing

I have been struggling to develop a code to avoid a big switch statement.
Basically I am given a set of tuples as input and now I would like to instantiate the appropriate class depending on the type specified in the tuple (first element of the tuple - e.g. ("Apple", ...)).
Currently I solved my problem by using a switch statement but this is a very bad idea if the number of classes increase in the future. Is there some elegant way to circumvent this issue?
Thank you!
class Apple {
var color = ""
}
class Banana {
var isTasty = false
}
let input = [("Apple", "green"),("Banana", "TRUE")]
for (type, value) in input {
switch type {
case "Apple":
Apple()
case "Banana":
Banana()
default:
print(value)
}
}
Check this out,
// Parent Class to group them
class Fruit {
var baseValue: Any
required init(_ this: Any) {
baseValue = this
(self as? Apple)?.color = this as! String
(self as? Banana)?.isTasty = this as! Bool
// You can add more subclasses here
}
}
class Apple: Fruit, Equatable {
var color = ""
func hash(into hasher: inout Hasher) {
hasher.combine(color)
}
static func == (lhs: Apple, rhs: Apple) -> Bool {
return lhs.color == rhs.color
}
}
class Banana: Fruit, Equatable {
var isTasty = false
func hash(into hasher: inout Hasher) {
hasher.combine(isTasty)
}
static func == (lhs: Banana, rhs: Banana) -> Bool {
return lhs.isTasty == rhs.isTasty
}
}
It's a little annoying that they have to conform to Fruit, Hashable, and Equatable. But it let's you do this, which answers your question:
let input: [(Fruit.Type,Any)] = [(Apple.self, "green"),(Banana.self, true)]
for (type, value) in input {
// Now you don't need that switch statement
let foo = type.init(value)
// Now you can use `as?` to find out what it is
print((foo as? Banana)?.isTasty)
// See, it prints `nil` first, then `Optional(true)` next.
// Which is how we want it to run
}
However, I think we can do even better.
enum Fruit {
case apple(color: String)
case banana(isTasty: Bool)
}
let input: [Fruit] = [.apple(color: "red"), .banana(isTasty: true)]
Much better.

Given an instance of a Swift object, can we test its class for the presence of a class function?

I've looked around, and haven't seen an answer to my question (but maybe I should be able to infer one).
I have an object, based on a protocol. It's an associated type protocol, with class operators that are defined, based on the type assigned to associatedtype, like so:
protocol GenericBaseProtocol {
associatedtype T
var myProperty: T {get set}
init(_ myProperty: T )
}
extension GenericBaseProtocol where T: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.myProperty == rhs.myProperty
}
}
So if I create a class, based on this, and give T an Equatable type, like so:
class IntClass: GenericBaseProtocol {
typealias T = Int
var myProperty: T = 0
required init(_ myProperty: T ) {
self.myProperty = myProperty
}
}
The resulting object should be comparable, like so:
let lhs = IntClass(3)
let rhs = IntClass(4)
let isEqual = lhs == rhs
Cool. Now, if I then create an instance with a non-Equatable type, like so:
class ArrayClass: GenericBaseProtocol {
typealias T = [String]
var myProperty: T = []
required init(_ myProperty: T ) {
self.myProperty = myProperty
}
}
And instantiate that, like so:
let lhs2A = ArrayClass(["HI"])
let rhs2A = ArrayClass(["Howaya"])
I will have compile-time syntax errors when I try this:
let isEqual = lhs2A == rhs2A
What I'd like to be able to do, is test the class object of lhs2A, and see if it implements static func ==(lhs: Self, rhs: Self) -> Bool
I'm not sure this can be done, but it would be nice for this article I'm writing up if I could add a runtime/guard proof to the playground, instead of simply commenting out the code.
Any ideas?
You could extend your protocol to give it a default implementation for the == operator in cases where the associated type is not Equatable.
This could also be used to provide a runtime indicator of wether the type is equatable or not.
for example:
extension GenericBaseProtocol where T: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.myProperty == rhs.myProperty
}
var isEquatable:Bool { return true }
}
extension GenericBaseProtocol {
static func ==(lhs: Self, rhs: Self) -> Bool {
return false
}
var isEquatable:Bool { return false }
}

generics struct implementing protocol with associated type

I am a bit stuck trying to define a container for my ui elements.
As I wanted something that encapsulates a non unique label, a value that can be any comparable object and a concept of being the preferred option I came up with the following protocol:
protocol OptionProtocol:Comparable {
associatedtype Key:Comparable
associatedtype Value:Comparable
var key:Key { get set }
var value:Value { get set }
var main:Bool { get set }
static func <(lhs: Self, rhs: Self) -> Bool
static func ==(lhs: Self, rhs: Self) -> Bool
}
extension OptionProtocol {
static func <(lhs: Self, rhs: Self) -> Bool {
let equalKeys = lhs.key == rhs.key
return equalKeys ? lhs.value < rhs.value : lhs.key < rhs.key
}
static func ==(lhs: Self, rhs: Self) -> Bool{
return (lhs.value == rhs.value) && (lhs.key == rhs.key)
}
}
Now I want to implement the protocol in a generic struct and I cant figure out how. What I want to do is
struct Option<Key, Value>: OptionProtocol {
var key:Key
var value:Value
var main:Bool
}
But the compiler complains that Type 'Option<Key, Value>' does not conform to protocol 'OptionProtocol'
Any pointer would be helpful
The answer was pretty simple. I needed to constraint Key and Value in the struct.
The following struct compiles as expected
struct Option<Key, Value>:OptionProtocol where Key:Comparable, Value:Comparable {
var key:Key
var value:Value
var main:Bool
}

Array of protocol type

I have checked all answers about this problem on stackoverflow, but still can not figure out how to fix this.
My model looks like this
protocol Commandable: Equatable {
var condition: Condition? {get set}
func execute() -> SKAction
}
And 3 structs which implement this protocol
struct MoveCommand: Commandable {
var movingVector: CGVector!
//MARK: - Commandable
var condition: Condition?
func execute() -> SKAction {
...
}
}
extension MoveCommand {
// MARK:- Equatable
static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector && lhs.condition == rhs.condition
}
}
struct RotateCommand: Commandable {
var side: RotationSide!
// MARK: - Commandable
var condition: Condition?
func execute() -> SKAction {
...
}
}
extension RotateCommand {
// MARK: - Equatable
static func ==(lhs: RotateCommand, rhs: RotateCommand) -> Bool {
return lhs.side == rhs.side && lhs.condition == rhs.condition
}
}
The problems start when I am trying to create third structure which has array of [Commandable]:
struct FunctionCommand: Commandable {
var commands = [Commandable]()
The compiler output: Protocol 'Commandable' can only be used as a generic constraint because it has Self or associated type requirements. Then i rewrote my struct in this way:
struct FunctionCommand<T : Equatable>: Commandable {
var commands = [T]()
I resolve this problem but new problem has appeared. Now i can't create FunctionCommand with instances of Rotate and Move command, only with instances of one of them :( :
let f = FunctionCommand(commands: [MoveCommand(movingVector: .zero, condition: nil),
RotateCommand(side: .left, condition: nil)], condition: nil)
Any Help would be appreciated.
Update: That article helped me to figure out - https://krakendev.io/blog/generic-protocols-and-their-shortcomings
What you need to do is to use type erasure, much like AnyHashable does in the Swift Standard Library.
You can't do:
var a: [Hashable] = [5, "Yo"]
// error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
What you have to do is to use the type-erased type AnyHashable:
var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")]
a[0].hashValue // => shows 5 in a playground
So your solution would be to first split the protocol in smaller parts and promote Equatable to Hashable (to reuse AnyHashable)
protocol Conditionable {
var condition: Condition? { get set }
}
protocol Executable {
func execute() -> SKAction
}
protocol Commandable: Hashable, Executable, Conditionable {}
Then create an AnyCommandable struct, like this:
struct AnyCommandable: Commandable, Equatable {
var exeBase: Executable
var condBase: Conditionable
var eqBase: AnyHashable
init<T: Commandable>(_ commandable: T) where T : Equatable {
self.condBase = commandable
self.exeBase = commandable
self.eqBase = AnyHashable(commandable)
}
var condition: Condition? {
get {
return condBase.condition
}
set {
condBase.condition = condition
}
}
var hashValue: Int {
return eqBase.hashValue
}
func execute() -> SKAction {
return exeBase.execute()
}
public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool {
return lhs.eqBase == rhs.eqBase
}
}
And then you can use it like this:
var a = FunctionCommand()
a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]
And you can easily access properties of commands, because AnyCommandable implements Commandable
a.commands[0].condition
You need to remember to now add Hashable and Equatable to all your commands.
I used those implementations for testing:
struct MoveCommand: Commandable {
var movingVector: CGVector!
var condition: Condition?
func execute() -> SKAction {
return SKAction()
}
var hashValue: Int {
return Int(movingVector.dx) * Int(movingVector.dy)
}
public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
return lhs.movingVector == rhs.movingVector
}
}
struct FunctionCommand: Commandable {
var commands = [AnyCommandable]()
var condition: Condition?
func execute() -> SKAction {
return SKAction.group(commands.map { $0.execute() })
}
var hashValue: Int {
return commands.count
}
public static func ==(lhs: FunctionCommand, rhs: FunctionCommand) -> Bool {
return lhs.commands == rhs.commands
}
}
I think it can be easily done by introduction of your own CustomEquatable protocol.
protocol Commandable: CustomEquatable {
var condition: String {get}
}
protocol CustomEquatable {
func isEqual(to: CustomEquatable) -> Bool
}
Then, you objects have to conform to this protocol and additionally it should conform Equitable as well.
struct MoveCommand: Commandable, Equatable {
let movingVector: CGRect
let condition: String
func isEqual(to: CustomEquatable) -> Bool {
guard let rhs = to as? MoveCommand else { return false }
return movingVector == rhs.movingVector && condition == rhs.condition
}
}
struct RotateCommand: Commandable, Equatable {
let side: CGFloat
let condition: String
func isEqual(to: CustomEquatable) -> Bool {
guard let rhs = to as? RotateCommand else { return false }
return side == rhs.side && condition == rhs.condition
}
}
All you need to do now is connect your CustomEquatable protocol to Swift Equatable through generic extension:
extension Equatable where Self: CustomEquatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.isEqual(to: rhs)
}
}
It's not a perfect solution, but now, you can store your objects in a array of protocol objects and use == operator with your objects as well. For example(I simplified objects a little bit):
let move = MoveCommand(movingVector: .zero, condition: "some")
let rotate = RotateCommand(side: 0, condition: "some")
var array = [Commandable]()
array.append(move)
array.append(rotate)
let equal = (move == MoveCommand(movingVector: .zero, condition: "some"))
let unequal = (move == MoveCommand(movingVector: .zero, condition: "other"))
let unequal = (move == rotate) // can't do this, compare different types
PS. Using var on struct is not a good practice, especially for performance reasons.
I believe the problem here is that the equatable protocol has self requirements. So you can solve you problem by removing equatable protocol from your Commandable protocol and make your your structs equatable instead. This will of course limit your protocol but maybe it is a trade-off that is reasonable?

Swift: Hashable struct with dictionary property

I have a struct in Swift that looks like this:
internal struct MapKey {
internal let id: String
internal let values: [String:String]
}
extension MapKey: Equatable {}
func ==(lhs: MapKey, rhs: MapKey) -> Bool {
return lhs.id == rhs.id && lhs.values == rhs.values
}
I now have the need to use MapKey as the key in a Swift dictionary, which requires MapKey to conform to the Hashable protocol.
What would a correct implementation of Hashable be for a struct like this one?
extension MapKey: Hashable {
var hashValue: Int {
return ??? // values does not have a hash function/property.
}
}
I've been doing some research but failed to identify what the proper way to hash a dictionary is, as I need to be able to generate a hash value for values property itself. Any help is much appreciated.
I think you need to review your data model if you have to use a whole struct as a dictionary key. Anyhow, here's one way to do it:
internal struct MapKey: Hashable {
internal let id: String
internal let values: [String:String]
var hashValue: Int {
get {
var hashString = self.id + ";"
for key in values.keys.sort() {
hashString += key + ";" + values[key]!
}
return hashString.hashValue
}
}
}
func ==(lhs: MapKey, rhs: MapKey) -> Bool {
return lhs.id == rhs.id && lhs.values == rhs.values
}
This assumes that you don't have semicolon (;) in id or in the keys and values of values. Hasable implies Equatable so you don't need to declare it conforming to Equatable again.
Since both id and values are immutable both are ok to use as basis for equals and hashValue.
However - if MapKey.id (which the name somewhat implies) uniquely identifies the MapKey (at least within the context of one dictionary)
then it is both easier and more performant to just use the MakKey.id as basis for == operator as well as hashValue
internal struct MapKey: Hashable {
internal let id: String
internal let values: [String:String]
var hashValue: Int {
get { return self.id.hashValue}
}
}
func ==(lhs: MapKey, rhs: MapKey) -> Bool {
return lhs.id == rhs.id
}
foundation data types are Hashable in Swift 4.2, you only need to let your MapKey struct to conform Hashable protocol:
struct MapKey: Hashable {
let id: String
let values: [String: String]
}
in case you want to use a class, you need conform hash(:) func like this:
class MapKey: Hashable {
static func == (lhs: MapKey, rhs: MapKey) -> Bool {
return lhs.id == rhs.id && lhs.values == rhs.values
}
let id: String = ""
let values: [String: String] = [:]
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(values)
}
}