TestsTested | ✓ |
LangLanguage | SwiftSwift |
License | MIT |
ReleasedLast Release | Sep 2016 |
SPMSupports SPM | ✓ |
Maintained by Tom Quist.
Equals is a Swift µframework to reduce boilerplate code when conforming to Equatable and Hashable protocols.
Add to your Package.swift dependencies:
import PackageDescription
let package = Package(
// ... your project details
dependencies: [
// As a required dependency
.Package(url: "ssh://[email protected]/tomquist/Equals.git", majorVersion: 2)
],
testDependencies: [
// As a test dependency
.Package(url: "ssh://[email protected]/tomquist/Equals.git", majorVersion: 2)
]
)
Lets start with a simple struct:
struct Person {
let firstName: String?
let lastName: String
let children: [Person]
}
To conform this type to Equatable
we first have to declare conformance, e.g. by providing an empty extension and provide an operator overload for ==
:
extension Person: Equatable {}
func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.firstName == rhs.firstName
&& lhs.lastName == rhs.lastName
&& lhs.children == rhs.children
}
As you can see, this is a lot of code for such a simple type and each property is listed twice.
Even worse, when conforming to Hashable
you additionally have to provide a complex hashValue
property:
extension Person: Hashable {
var hashValue: Int {
var result = 17
result = 31 &* result &+ (firstName?.hashValue ?? 0)
result = 31 &* result &+ lastName.hashValue
for child in children {
result = 31 &* result &+ child.hashValue
}
return result
}
}
Using Equals, this is a lot easier. To conform to Hashable
, all you have to do is to conform to the EqualsHashable
protocol:
extension Person: EqualsHashable {
static let hashes: Hashes<Person> = Hashes()
.append {$0.firstName}
.append {$0.lastName}
.append {$0.children}
}
If you don’t need hashing capabilities, just conform to the EqualsEquatable
protocol:
extension Person: EqualsEquatable {
static let equals: Equals<Person> = Equals()
.append {$0.firstName}
.append {$0.lastName}
.append {$0.children}
}
That’s it! Now you can compare your type, using the ==
operator, put it into Set
s or use it as a Dictionary
key.
Equals currently provides append
functions for four types of properties:
Equatable
/Hashable
propertiesOptional
properties of type Equatable
/Hashable
CollectionType
properties where the elements are Equatable
/Hashable
Sometimes, you explicitly have to specify which append method to use. E.g. lets change the property children
of our Person
example above into type Set<Person>
. Because Set
already conforms to Hashable
, we now get a compiler error:
Ambiguous use of 'append(hashable:)'
This is because there are potentially several append
methods that could be used in this situation. To avoid this error, we can change our implementation of EqualsHashable
into this:
extension Person: EqualsHashable {
static let hashes: Hashes<Person> = Hashes()
.append {$0.firstName}
.append {$0.lastName}
.append(hashable: {$0.children})
}