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

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.

Related

Swift: Protocol With associatedType

I have a question about Protocol with associated type, why I can not make the protocol a type of my instance for example:
I know I can use Type Erasure to fix the issue, but why protocol with an associated type does not like to be a type of an instance, and if you will say because the associated type is also used as a constraint, well I want to implement the properties inside the protocol not inside its extensions since protocol extensions has the power to control who can access its properties, why we still have this issue.
Thank you.
There are lots of articles and answers (like this one) out there describing why but in summary, It needs associatedtype. Variables can not have an associatedtype. So alongside with Type Erasure method (that you don't want), you can simply make it opaque with adding some keyword to the type:
var objectA: some ProtocolA = A()

What is the use of hashable protocol in swift4?

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.

In Swift, from a technical standpoint, why does the compiler care if a protocol can only be used as a generic constraint?

In Swift, from a technical standpoint, why does the compiler care if a protocol can only be used as a generic constraint?
Say I have:
protocol Fooable {
associated type Bar: Equatable
func foo(bar: Bar) {
bar==bar
}
}
Why can't I later declare a func that takes a Fooable object as an argument?
It seems to me that the compiler should only care that a given Fooable can be sent a message "foo" with an argument "bar" that is an Equatable and therefore responds to the message, "==".
I understand Swift is statically typed, but why should Swift even really care about type in this context, since the only thing that matters is whether or not a given message can be validly sent to an object?
I am trying to understand the why behind this, since I suspect there must be a good reason.
In your example above, if you wrote a function that takes a Fooable parameter, e.g.
func doSomething(with fooable:Fooable) {
fooable.foo(bar: ???) // what type is allowed to be passed here? It's not _any_ Equatable, it's the associated type Bar, which here would be...???
}
What type could be passed into fooable.foo(bar:)? It can't be any Equatable, it must be the specific associated type Bar.
Ultimately, it boils down the the problem that protocols that reference "Self" or have an associated type end up having different interfaces based on which concrete implementation has conformed (i.e. the specific type for Self, or the specific associated type). So these protocols can be considered as missing information about types and signatures needed to address them directly, but still serve as templates for conforming types and so can be used as generic constraints.
For example, the compiler would accept the function written like this:
func doSomething<T: Fooable>(with fooable:T, bar: T.Bar) {
fooable.foo(bar: bar)
}
In this scenario we aren't trying to address the Fooable protocol as a protocol. Instead, we are accepting any concrete type, T, that is itself constrained to conform to Fooable. But the compiler will know the exact concrete type of T each time you call the function, so it therefore will know the exact associated type Bar, and will know exactly what type may be passed as a parameter to fooable.foo(bar:)
More Details
It may help to think of "generic protocols" — i.e. protocols that have an associated type, including possibly the type Self — as something a little different than normal protocols. Normal protocols define messaging requirements, as you say, and can be used to abstract away a specific implementation and address any conforming type as the protocol itself.
Generic protocols are better understood as part of the generics system in Swift rather than as normal protocols. You can't cast to a generic protocol like Equatable (no if let equatable = something as? Equatable) because as part of the generic system, Equatable must be specialized and understood at compile time. More on this below.
What you do get from generic protocols that is the same as normal protocols is the concept of a contract that conforming types must adhere to. By saying associatedtype Bar: Equatable you are getting a contract that the type Bar will provide a way for you to call `func ==(left:Bar, right: Bar) -> Bool'. It requires conforming types to provide a certain interface.
The difference between generic protocols and normal protocols is that you can cast to and message normal protocols as the protocol type (not a concrete type), but you must always address conformers to generic protocols by their concrete type (just like all generics). This means normal protocols are a runtime feature (for dynamic casting) as well as a compile time feature (for type checking). But generic protocols are only a compile time feature (no dynamic casting).
Why can't we say var a:Equatable? Well, let's dig in a little. Equatable means that one instance of a specific type can be compared for equality with another instance of the same type. I.e. func ==(left:A, right:A) -> Bool. If Equatable were a normal protocol, you would say something more like: func ==(left:Equatable, right:Equatable) -> Bool. But if you think about that, it doesn't make sense. String is Equatable with other Strings, Int is Equatable with other Ints, but that doesn't in any way mean Strings are Equatable with Ints. If the Equatable protocol just required the implementation of func ==(left:Equatable, right:Equatable) -> Bool for your type, how could you possibly write that function to compare your type to every other possible Equatable type now and in the future?
Since that's not possible, Equatable requires only that you implement == for two instances of Self type. So if Foo: Equatable, then you must only define == for two instances of Foo.
Now let's look at the problem with var a:Equatable. This seems to make sense at first, but in fact, it doesn't:
var a: Equatable = "A String"
var b: Equatable = 100
let equal = a == b
Since both a and b are Equatable, we could be able to compare them for equality, right? But in fact, a's equality implementation is limited to comparing a String to a String and b's equality implementation is limited to comparing an Int to an Int. So it's best to think of generic protocols more like other generics to realize that Equatable<String> is not the same protocol as Equatable<Int> even though they are both supposedly just "Equatable".
As for why you can have a dictionary of type [AnyHashable: Any], but not [Hashable: Any], this is becoming more clear. The Hashable protocol inherits from Equatable, so it is a "generic protocol". That means for any Hashable type, there must be a func ==(left: Self, right:Self) -> Bool. Dictionaries use both the hashValue and equality comparisons to store and retrieve keys. But how can a dictionary compare a String key and an Int key for equality, even if they both conform to Hashable / Equatable? It can't. Therefore, you need to wrap your keys in a special "type eraser" called AnyHashable. How type erasers work is too detailed for the scope of this question, but suffice it to say that a type eraser like AnyHashable gets instantiated with some type T: Hashable, and then forward requests for a hashValue to its wrapped type, and implements ==(left:AnyHashable, right: AnyHashable) -> Bool in a way that also uses the wrapped type's equality implementation. I think this gist should give a great illustration of how you can implement an "AnyEquatable" type eraser.
https://gist.github.com/JadenGeller/f0d05a4699ddd477a2c1
Moving onward, because AnyHashable is a single concrete type (not a generic type like the Hashable protocol is), you can use it to define a dictionary. Because every single instance of AnyHashable can wrap a different Hashable type (String, Int, whatever), and can also produce a hashValue and be checked for equality with any other AnyHashable instance, it's exactly what a dictionary needs for its keys.
So, in a sense, type erasers like AnyHashable are a sort of implementation trick that turns a generic protocol into something like a normal protocol. By erasing / throwing away the generic associated type information, but keeping the required methods, you can effectively abstract the specific conformance of Hashable into general type "AnyHashable" that can wrap anything Hashable, but be used in non-generic circumstances.
This may all come together if you review that gist for creating an implementation of "AnyEquatable": https://gist.github.com/JadenGeller/f0d05a4699ddd477a2c1 and then go back an see how you can now turn this impossible / non-compiling code from earlier:
var a: Equatable = "A String"
var b: Equatable = 100
let equal = a == b
Into this conceptually similar, but actually valid code:
var a: AnyEquatable = AnyEquatable("A String")
var b: AnyEquatable = AnyEquatable(100)
let equal = a == b

Are type-erased Any... structs necessary for non-generic protocols?

When defining a generic Swift protocol (that is, a protocol with at least one associatedtype) for a framework, it's common practice to also provide an Any... struct, e.g. SomethingType and AnySomething. For example, the standard library does this with AnySequence.
Is this necessary for a non-generic protocol? In that case, you can refer to the protocol type directly, so it seems that the protocol itself is already a type-erased version?
A protocol that does not have an associated type can easily be used as a Type in its own right. This is often done to allow diverse concrete types to be stored in collections identifying them only by a common protocol that all the concrete types implement.
Or to put it another way "type erasing" is a technique for dealing with protocols that have associated types. If your protocol does not have associated types, there is no need to employ the technique.

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.