Cache results of Swift hash(into:) Hashable protocol requirement - swift

I have a class being heavily used in Sets and Dictionaries.
For performance reasons this class implements Hashable in a old way and caches the computed hash:
let hashValue: Int
init(...) {
self.hashValue = ...
}
In Xcode 10.2 I see a warning, that hashValue is deprected and will stop being a protocol requirement soon.
What bothers me is a lack of ability to cache the computed hash anyhow, because hash(into:) does not return anything.
func hash(into hasher: inout Hasher) {
hasher.combine(...)
}
Consider the following example in a playground
class Class: Hashable {
let param: Int
init(param: Int) {
self.param = param
}
static func ==(lhs: Class, rhs: Class) -> Bool {
return lhs.param == rhs.param
}
public func hash(into hasher: inout Hasher) {
print("in hash")
hasher.combine(param)
}
}
var dict = [Class: Int]()
let instance = Class(param: 1)
dict[instance] = 1
dict[instance] = 2
You will see the following logs
in hash
in hash
in hash
I have no idea, why we see 3 calls instead of 2, but we do =).
So, every time you use a same instance as a dictionary key or add this instance into a set, you get a new hash(into:) call.
In my code such an overhead turned out to be very expensive. Does anyone know a workaround?

One option is to create your own Hasher, feed it the "essential components" of your instance and then call finalize() in order to get out an Int hash value, which can be cached.
For example:
class C : Hashable {
let param: Int
private lazy var cachedHashValue: Int = {
var hasher = Hasher()
hasher.combine(param)
// ... repeat for other "essential components"
return hasher.finalize()
}()
init(param: Int) {
self.param = param
}
static func ==(lhs: C, rhs: C) -> Bool {
return lhs.param == rhs.param
}
public func hash(into hasher: inout Hasher) {
hasher.combine(cachedHashValue)
}
}
A couple of things to note about this:
It relies on your "essential components" being immutable, otherwise a new hash value would need calculating upon mutation.
Hash values aren't guaranteed to remain stable across executions of the program, so don't serialise cachedHashValue.
Obviously in the case of storing a single Int this won't be all that effective, but for more expensive instances this could well help improve performance.

Related

Segmentation Fault in Swift

I get the following error when running swift run inside of an executable Swift Package:
zsh: segmentation fault swift run
I have been able to boil the code down to the following:
enum MyEnum {
case FirstCase
case SecondCase
case Other
}
struct MyEnumCollection {
private var enums: [MyEnum]
}
extension MyEnumCollection: RangeReplaceableCollection {
public init() {
self.enums = []
}
}
extension MyEnumCollection: Collection {
public var startIndex: Int {
0
}
public var endIndex: Int {
self.enums.count
}
public subscript(position: Int) -> MyEnum {
return self.enums[position]
}
public func index(after i: Int) -> Int {
return self.enums.index(after: i)
}
}
var collection = MyEnumCollection()
collection.append(MyEnum.FirstCase)
The segmentation fault happens on the last line, at the append statement.
Can someone help me understand why this is happening and how I should fix this?
Update
Thanks to a comment from #MartinR it turns out that a even better solution is to implement replaceSubrange(_:with:) from the RangeReplaceableCollection protocol instead of append
mutating func replaceSubrange<C>(_ subrange: Range<Int>, with newElements: C) where C : Collection, MyEnum == C.Element {
self.enums.replaceSubrange(subrange, with: newElements)
}
Old solution
You need to implement append() as well
public mutating func append(_ newElement: MyEnum) {
enums.append(newElement)
}
There is a default implementation of this function but of course it has no knowledge about your internal data source enums so it is not usable.
Going forward you might also need to implement other functions that has a default implementation.
Another thing, personally I would use the properties of the Array class as well when conforming to the protocol.
public var startIndex: Int {
return enums.startIndex
}
public var endIndex: Int {
return self.enums.endIndex
}

Implementing a hash combiner in Swift

I'm extending a struct conform to Hashable. I'll use the DJB2 hash combiner to accomplish this.
To make it easy to write hash function for other things, I'd like to extend the Hashable protocol so that my hash function can be written like this:
extension MyStruct: Hashable {
public var hashValue: Int {
return property1.combineHash(with: property2).combineHash(with: property3)
}
}
But when I try to write the extension to Hashable that implements `combineHash(with:), like this:
extension Hashable {
func combineHash(with hashableOther:Hashable) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}
… then I get this compilation error:
/Users/benjohn/Code/Nice/nice/nice/CombineHash.swift:12:43: Protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements
Is this something that Swift won't let me do, or am I just doing it wrong and getting an unhelpful error message?
Aside A comment from JAL links to a code review of a swift hash function that is also written by Martin who provides the accepted answer below! He mentions a different hash combiner in that discussion, which is based on one in the c++ boost library. The discussion really is worth reading. The alternative combiner has fewer collisions (on the data tested).
Use the method hash(into:) from the Apple Developer Documentation:
https://developer.apple.com/documentation/swift/hashable
struct GridPoint {
var x: Int
var y: Int
}
extension GridPoint: Hashable {
static func == (lhs: GridPoint, rhs: GridPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
func hash(into hasher: inout Hasher) {
hasher.combine(x)
hasher.combine(y)
}
}
You cannot define a parameter of type P if P
is a protocol which has Self or associated type requirements.
In this case it is the Equatable protocol from which Hashable
inherits, which has a Self requirement:
public static func ==(lhs: Self, rhs: Self) -> Bool
What you can do is to define a generic method instead:
extension Hashable {
func combineHash<T: Hashable>(with hashableOther: T) -> Int {
let ownHash = self.hashValue
let otherHash = hashableOther.hashValue
return (ownHash << 5) &+ ownHash &+ otherHash
}
}

Make struct Hashable?

I'm trying to create a dictionary of the sort [petInfo : UIImage]() but I'm getting the error Type 'petInfo' does not conform to protocol 'Hashable'. My petInfo struct is this:
struct petInfo {
var petName: String
var dbName: String
}
So I want to somehow make it hashable but none of its components are an integer which is what the var hashValue: Int requires. How can I make it conform to the protocol if none of its fields are integers? Can I use the dbName if I know it's going to be unique for all occurrences of this struct?
Simply return dbName.hashValue from your hashValue function. FYI - the hash value does not need to be unique. The requirement is that two objects that equate equal must also have the same hash value.
struct PetInfo: Hashable {
var petName: String
var dbName: String
var hashValue: Int {
return dbName.hashValue
}
static func == (lhs: PetInfo, rhs: PetInfo) -> Bool {
return lhs.dbName == rhs.dbName && lhs.petName == rhs.petName
}
}
As of Swift 5 var hashValue:Int has been deprecated in favour of func hash(into hasher: inout Hasher) (introduced in Swift 4.2), so to update the answer #rmaddy gave use:
func hash(into hasher: inout Hasher) {
hasher.combine(dbName)
}

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 */
}
}

Add "for in" support to iterate over Swift custom classes

As we know, we can use the for..in loop to iterate across Arrays or Dictionaries. However, I would like to iterate over my own CustomClass like this:
for i in CustomClass {
someFunction(i)
}
What operations/protocols does CustomClass have to support for this to be possible?
Say you have a class "Cars" that you want to be able to iterate over using a for..in loop:
let cars = Cars()
for car in cars {
println(car.name)
}
The simplest way is to use AnyGenerator with the classes like this:
class Car {
var name : String
init(name : String) {
self.name = name
}
}
class Cars : SequenceType {
var carList : [Car] = []
func generate() -> AnyGenerator<Car> {
// keep the index of the next car in the iteration
var nextIndex = carList.count-1
// Construct a AnyGenerator<Car> instance, passing a closure that returns the next car in the iteration
return anyGenerator {
if (nextIndex < 0) {
return nil
}
return self.carList[nextIndex--]
}
}
}
To try a complete working sample add the two classes above and then try to use them like this, adding a couple of test items:
let cars = Cars()
cars.carList.append(Car(name: "Honda"))
cars.carList.append(Car(name: "Toyota"))
for car in cars {
println(car.name)
}
That's it, simple.
More info: http://lillylabs.no/2014/09/30/make-iterable-swift-collection-type-sequencetype
All of the above answers can be a little tricky. If you have an array in your class, which you want to iterate over (like in #Lee Whitney's answer), there's a much simpler way to implement it. You have the following class, CustomClass:
class CustomClass: SequenceType {
let array: [String]
init(array: [String]) {
self.array = array
}
func generate() -> IndexingGenerator<[String]> {
return array.generate()
}
}
Simple as that. Tested to work in the latest Xcode version (6.1 at the time of writing), and iOS 8.1.2. This code should be stable through future versions, though.
P.S. With generics, you can easily do your own Array replica by following this pattern, and only implement the methods which you want.
#Matt Gibson is correct. However, I would like to add more information for future reference.
From Advanced Swift:
This code:
for x in someSequence {
...
}
Is converted into this:
var __g = someSequence.generate()
while let x = __g.next() {
...
}
Therefore, one must adopt Sequence, which gives the class generate() and next(). Here are these protocols:
protocol Generator {
typealias Element
mutating func next() -> Element?
}
protocol Sequence {
typealias GeneratorType : Generator
func generate() -> GeneratorType
}
That would be the SequenceType protocol, and its related Generator protocol.
The SequenceType protocol says that the class must implement generate(), which returns something that conforms to the Generator protocol, which is the bit that does the actual work; the Generator protocol is the one with the all-important next() method.
There's an example of implementing it to allow for..in in the WWDC 2014 video "Advanced Swift" (in the generics example "A Simple Generic Stack", starting around slide 183.)
The basic info on which protocol to implement for for..in is in the Statements section of the documentation, which gives a brief overview of SequenceType and Generator
NOTE AnyGenerator and SequenceType are old types that do not exist in recent versions. You need to implement Sequence protocol now.
There are two ways to implement Sequence.
Conform to Sequence, IteratorProtocol at the same time by just implementing next() method. This approach is the simplest and there is an example in the headers. See Sequence.swift. Implementing both protocols at the same time could be non-realistic or not fulfill your needs. (It might prevent two different instances to be iterated at the same time, etc)
Conform to Sequence and return an object that implements IteratorProtocol. I think this is the most common case in real world classes (when things become a bit complicated, not Hello Worlds). There is also an example in the Sequence.swift
Below is an example of approach 2. An custom class (Linked List) which is iterable:
/// Linked List Node:
public class LinkedListNode <T> {
public internal(set) var value: T
public internal(set) var next: LinkedListNode<T>?
internal init(_ value: T) {
self.value = value
self.next = nil
}
}
/// Linked List with append method only.
public class LinkedList<T> {
public internal(set) var first: LinkedListNode<T>? = nil
public internal(set) var last: LinkedListNode<T>? = nil
/// Appends a new node.
public func append(_ value: T) {
if first == nil {
first = LinkedListNode(value)
last = first
} else {
last.next = LinkedListNode(value)
last = last.next
}
}
}
Finally the Sequence implementation
/// Sequence protocol adoption. It allows `for ... in` and a bunch of other methods too.
extension LinkedList: Sequence {
/// Iterator implementation
public class Iterator<T>: IteratorProtocol {
/// Maintain a ref to current element so next element can be reached
var cur: LinkedListNode<T>?
/// IteratorProtocol protocol requirement
public func next() -> T? {
let res = cur?.value
cur = cur?.next
return res
}
}
/// Sequence protocol requirement
public func makeIterator() -> Iterator<T> {
let g = LinkedList.Iterator()
g.cur = first
return g
}
}
Usage:
let linkedList = LinkedList<Int>()
linkedList.append(3)
linkedList.append(6)
linkedList.append(9)
linkedList.append(12)
for element in linkedList {
print(element)
}
let odds = linkedList.filter { return $0 % 2 == 0 }
print(odds)
The accepted answer is correct, and up until recently was the accepted way to address this. However, given the introduction of Protocol Extensions in Swift 2.0, rather than conformance to SequenceTypeand implementing func generate() -> GeneratorOf<Car> there is now an abstract base class that handles the implementation of this functionality for you called AnyGenerator<T> (see Apple docs) since GeneratorOf<T> no longer exists.
What this means is that you can simply subclass this abstract base class, and by doing do, inherit all of the functionality of the aforementioned protocol conformance:
class Cars: AnyGenerator<Car> {
private var carList = [Car]()
private var currentIndex:Int
...
}
One then need only override the next() method declared by the GeneratorType protocol (which AnyGenerator<T> also conforms to) in order to define the desired iteration behavior:
class Cars: AnyGenerator<Car> {
private var carList = [Car]()
private var currentIndex:Int
override func next() -> Car? {
if (currentIndex < self.carList.count) {
currentIndex++
return self.carList[currentIndex-1]
} else {
currentIndex = 0;
return nil
}
}
}