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

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.

Related

Is there an equivalent in swift to Go's empty interface?

Is there an equivalent in Swift to pass as an argument an empty interface{} like in Go?
I am not very familiar with Go, but I think the Swift equivalent would be an argument of type Any or AnyObject. You can't do much with such an argument other than try to cast it to a more specific type.
Go's interfaces and Swift's protocols are quite different:
Golang's interfaces are "structural" (akin to C++'s "Concepts"), meaning that their identity is defined by their structure. If a go struct has the structure required by an interface, it implicitly implements that interface. That is, the struct doesn't say anywhere "I am strust S, and I implement interface I."
Swift's protocols are "nominal", meaning that their identity is defined their name. If a Swift struct fulfills all of the requirements of a protocol, it doesn't conform to that protocol, unless an explicit struct S: P { ... } declaration is made (the body of that declaration can even be empty, but it's still necessary for the conformance to exist).
The closest analogue to interface{} in Swift is Any. It's built-in protocol to which all type conform. It gets special treatment, it's defined by the compiler, and has hard-coded logic to make all other types conform to it. You won't see protocol Any {} or struct S: Any {} declared anywhere explicitly. AnyObject is similar, and also gets special treatment. But no other Swift protocols do. Their conformance need to be explicit.
If I am not mistaking Swift's equivalent would be:
protocol EmptyProtocol {
}
In swift interfaces are called protocols don't ask me :D
Are you trying to do type erasure or something? Just curious...

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.

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.

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

How to constrain function parameter's protocol's associated types

For fun, I am attempting to extend the Dictionary class to replicate Python's Counter class. I am trying to implement init, taking a CollectionType as the sole argument. However, Swift does not allow this because of CollectionType's associated types. So, I am trying to write code like this:
import Foundation
// Must constrain extension with a protocol, not a class or struct
protocol SingletonIntProtocol { }
extension Int: SingletonIntProtocol { }
extension Dictionary where Value: SingletonIntProtocol { // i.e. Value == Int
init(from sequence: SequenceType where sequence.Generator.Element == Key) {
// Initialize
}
}
However, Swift does not allow this syntax in the parameter list. Is there a way to write init so that it can take any type conforming to CollectionType whose values are of type Key (the name of the type used in the generic Dictionary<Key: Hashable, Value>)? Preferably I would not be forced to write init(from sequence: [Key]), so that I could take any CollectionType (such as a CharacterView, say).
You just have a syntax problem. Your basic idea seems fine. The correct syntax is:
init<Seq: SequenceType where Seq.Generator.Element == Key>(from sequence: Seq) {
The rest of this answer just explains why the syntax is this way. You don't really need to read the rest if the first part satisfies you.
The subtle difference is that you were trying to treat SequenceType where sequence.Generator.Element == Key as a type. It's not a type; it's a type constraint. What the correct syntax means is:
There is a type Seq such that Seq.Generator.Element == Key, and sequence must be of that type.
While that may seem to be the same thing, the difference is that Seq is one specific type at any given time. It isn't "any type that follows this rule." It's actually one specific type. Every time you call init with some type (say [Key]), Swift will create an entirely new init method in which Seq is replaced with [Key]. (In reality, Swift can sometimes optimize that extra method away, but in principle it exists.) That's the key point in understanding generic syntax.
Or you can just memorize where the angle-brackets go, let the compiler remind you when you mess it up, and call it day. Most people do fine without learning the type theory that underpins it.