What is the use of hashable protocol in swift4? - swift

please explain the use of hashable protocol with implementation in swift.
Apple defines hashable as “a type that provides an integer a hash value.” Okay, but what’s a hash value?

To make an object conform to Hashable we need to provide a hashValue property that will return a unique, consistent number for each instance.
The Hashable protocol inherits from Equatable, so you may also need to implement an == function.
Note: If two objects compare as equal using == they should also generate the same hash value, but the reverse isn’t true – hash collisions can happen.
Before Swift 4.1, conforming to Hashable was complex because you needed to calculate a hashValue property by hand.
In Swift 4.1 this improved so that hashValue could be synthesized on your behalf if all the properties conform to Hashable .
Swift 4.2 introduces a new Hasher struct that provides a randomly seeded, universal hash function to make all our lives easier. Refer for more

Quick answer:
We use hash integer into object to be able to quickly identify object that are equals by getting the object instance in front of the index that we are looking for.
Not quick answer:
When you are dealing with list in order to find an object you need to iterate over all your array and compare property to find the one you are looking for, this can slowdown your app as the list get bigger.
When you use SET, the mechanism under the hood use hash indexes to find an object so it take you only the time to calculate once the index you are looking for then you can access straight forward to your object, THIS IS SO COOL ISN'T.
In order to use SET the object need to conform to Hashable protocol since Swift 4.1, if your class or struct and all properties conform to Hashable then the conformity with Hashable and Equatable protocol is automatically done for you under the hood.
If you do not meet those requirments then you will have to make sure that you conform to Equatable and Hashable protocol.
Equatable protocol need to overide static func ==(..) in order to compare you object.
Hashable protocol need to provide as far as you can a unique integer value hashValue which need to be the same within two object when they are equals.
Hope this help

If an object conforms to the hashable protocol, it needs to have a hashValue, as you mentioned. The hashValue can be used to compare objects / uniquely identify the object.
You can compare objects in two ways:
=== function. This checks object references (can only be used with classes). It checks if the left object has the same reference to the right object. Even if both objects have exactly the same property values BUT they do have a different reference, it returns false.
== function (Equatable protocol). It checks if the objects are equal to eachother based on the static func ==. You can return the hashValue of the object. In that way, you can say objects are equal to eachtoher based on the properties, rather than reference.
If you provide your own hashValue, you can say objects are equal to eachother in a way you say objects are equal to eachother, regardless of the reference to the object. You can use objects in a Set that conform to the hashable protocol, because a Set checks if objects are equal to eachother based on the hashValue.

The Hashable documentation give one concrete example of what it's for:
You can use any type that conforms to the Hashable protocol in a set or as a dictionary key.
You can think of a hash value as a quick approximation of equality. Two elements that are equal will have the same hash value but two elements with the same hash value are not guaranteed to actually be equal.

Related

In SwiftUI, what's the different ForEach without Identifier and with Identifier?

In SwiftUI, in the ViewBuilder, we have to use ForEach instead of for.
However, there are two ways of doing i.e.
ForEach(1...count, id:\.self)
and
ForEach(1..<(count+1))
Other than the syntax being different, is there any different use case for them?
Joakim has answered your question in the comments.
The second listed alternative can be used as long as the datatype being referenced is Identifiable. That means it is a class or has been declared as conforming to the Identifiable protocol. You can get Identifiable almost for free on your own objects by declaring conformance. The compiler will help you if you say you conform but don't, so that's a good place to start.
From Apple's Online Documentation:
Identifiable provides a default implementation for class types (using ObjectIdentifier), which is only guaranteed to remain unique for the lifetime of an object. If an object has a stronger notion of identity, it may be appropriate to provide a custom implementation.
The first alternative exists for cases when it doesn't conform to Identifiable.

How does `NSAttibutedString` equate attribute values of type `Any`?

The enumerateAttribute(_:in:options:using:) method of NSAttributedString appears to equate arbitrary instances of type Any. Of course, Any does not conform to Equatable, so that should not be possible.
Question: How does the method compare one instance of Any to another?
Context: In Swift, I am subclassing NSTextStorage, and have need to provide my own implementation of this method in Swift.
Observations:
NSAttributedString attributes come in key-value pairs, with the keys being instances of type NSAttributedString.Key and the values being instances of type Any?, with each pair being associated with one or more ranges of characters in the string. At least, that is how the data structure appears from the outside; the internal implementation is opaque.
The enumerateAttribute method walks through the entire range of an NSAttributedString, effectively identifying each different value corresponding to a specified key, and with the ranges over which that value applies.
The values corresponding to a given key could be of multiple different types.
NSAttributedString seemingly has no way of knowing what underlying types the Any values might be, and thus seemingly no way of type casting in order to make a comparison of two given Any values.
Yet, the method somehow is differentiating among ranges of the string based on differences in the Any values.
Interestingly, the method is able to differentiate between values even when the underlying type does not conform to Equatable. I take this to be a clue that the method may be using some sort of reflection to perform the comparison.
Even more interesting, the method goes so far as to differentiate between values when the underlying type does conform to Equatable and the difference between two values is a difference that the specific implementation of Equatable intentionally ignores. In other words, even if a == b returns true, if there is a difference in opaque properties of a and b that are ignored by ==, the method will treat the values as being different, not the same.
I assume the method bridges to an implementation in ObjC.
Is the answer: It cannot be done in Swift?
As you know, Cocoa is Objective-C, so these are Objective-C NSDictionary objects, not Swift Dictionary objects. So equality comparison between them uses Objective-C isEqual, not Swift ==. We are not bound by Swift strict typing, the Equatable protocol, or anything else from Swift.
To illustrate, here's a slow and stupid but effective implementation of style run detection:
let s = NSMutableAttributedString(
string: "howdy", attributes: [.foregroundColor:UIColor.red])
s.addAttributes([.foregroundColor:UIColor.blue],
range: NSRange(location: 2, length: 1))
var lastatt = s.attributes(at: 0, effectiveRange: nil)
for ix in 1..<5 {
let newatt = s.attributes(at:ix, effectiveRange:nil)
if !(newatt as NSDictionary).isEqual(to: lastatt) {
print("style run ended at \(ix)")
lastatt = newatt
}
}
That correctly prints:
style run ended at 2
style run ended at 3
So since it is always possible to compare the attributes at any index with the attributes at another, it is possible to implement attribute enumeration in Swift. (Whether that's a good idea is another question.)

Binary operator '==' cannot be applied to two 'Equatable' operands... what?

You can see in the image below that I was trying to extend the Collection protocol to include a method called removingDuplicates, which is supposed to do exactly what it says. The error that the compiler is displaying seems to directly contradict the definition of the Equatable protocol. Is this a bug or am I misunderstanding something?
Replace Element == Equatable with Element: Equatable.
The == function (all operators are actually functions in Swift) is a requirement of the Equatable protocol, which means it must be used with some concrete implementations of the protocol.
Another aspect is that Collection is a generic type, and its Element associated type will need to eventually be also filled with a concrete type, and == Equatable doesn't help here.
Actually it's not even possible to have a collection of generic Equatable values, as Equatable is a protocol with Self requirements, thus it can be directly referenced in a lot of places, e.g. [Equatable], one reason being the fact that that declaration can't satisfy the "collections are homogenous" requirement as you'd be able ot place two completely unrelated types in the array that way.
What you need to do is to transform the equality where clause to a conformance one: extension Collection where Element: Equatable. This moves the burden of providing an actual implementation on the user of the extension. And allows you to use the support brought by the Equatable type.

Swift work around to make `AnyObject.Type` conform to `Equatable`?

I would like to make AnyClass (AKA AnyObject.Type) conform to Equatable so that when I have an array with AnyClass elements (Array<AnyClass>), I can call remove(Element:), but this requires Element to conform to Equatable.
Since Swift 3 you could use AnyHashable as a replacement for AnyObject. It represents any value which conforms to the Equatable protocol.
Instead of
var array:[AnyObject] = []
just write
var array:[AnyHashable] = []
I don't actually think what your trying to acheive is possible, or whether you should even try to do it in this way.
Classes are generally represent real world objects, whether this is a car, a view or soemthing completely different. So it's very difficult to say is ANY custom I class I create the same as this other custom class I created.
Swift just doesn't know how to compare them, what makes them the same.
The simplest way to achieve what you want here would be to define a custom protocol/interface that does represent the generic version of the classes you will use in this application and then ensure each conforms to that and also equatable. Then you should be able to do something like:
var objs = Array<MyAppClassesProtocol>()
and also use remove(element:)

indexOf(Element) doesn't exist for [Foo.Type] arrays

Swift's CollectionType provides two indexOf methods: one that takes an element directly, and one that takes a predicate function. If I have an array of type [Foo.Type] (for any class Foo), the former doesn't exist; there's only the predicate version of indexOf. Why is this?
The indexOf method that takes an element requires that the element must conform to the Equatable protocol. It's defined in a constrained protocol extension, so it only shows up when that constraint holds true.
Metatypes (of the form SomeType.Type) cannot themselves conform to protocols (current as of Swift 2.1). Therefore even though you can define an == operator at global scope that operates on metatypes, you can't actually have a metatype conform to the Equatable protocol. This is a known language limitation.
In some cases (e.g. when using types as keys in a dictionary) you may be able to use the standard library ObjectIdentifier type to work around this limitation.