What does [[Element].Element] mean in Swift's == operator overload? - swift

Swift's Array type implements Equatable protocol in a way that == and != operators are overloaded:
extension Array : Equatable where Element : Equatable {
/// - Parameters:
/// - lhs: An array to compare.
/// - rhs: Another array to compare.
public static func == (lhs: [[Element].Element], rhs: [[Element].Element]) -> Bool
public static func != (lhs: [[Element].Element], rhs: [[Element].Element]) -> Bool
}
I've got three questions:
What is [[Element].Element]?
How to read that?
Why I cannot use that construct in my Swift code?
So far my reasoning is:
[Element] is a type definition, i.e. an array of types denoted by
Element (Element is a placeholder type name).
Based on 1, next I reckon outermost brackets denote another array, BUT...
I can't figure out what [Element].Element means as .Element is puzzling for me.

Generally, TypeA.TypeB can denote a nested type or type alias TypeB
inside TypeA, or an associated type TypeB of a protocol TypeA.
Array conforms to Sequence, and that has an associatedtype Element
for the type of the elements returned from its iterator. For arrays
that is equal to the array's element type. So for any type T:
Array<T>.Element == T
and consequently,
[Array<T>.Element] == [T]
Example:
print(type(of: [Array<Int>.Element].self))
// Array<Int>.Type
However, using the bracket notation for the inner array is not accepted
by the compiler:
print(type(of: [[Int].Element].self))
// Expected member name or constructor call after type name
Now back to your question: The actual definition of that == operator is
extension Array : Equatable where Element : Equatable {
public static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool {
// ...
}
}
The “generated interface” is, as you noticed:
extension Array : Equatable where Element : Equatable {
public static func == (lhs: [[Element].Element], rhs: [[Element].Element]) -> Bool
}
So apparently, the “interface generator” interprets the Element
in lhs: Array<Element> not as the placeholder type, but as the associated
Element type of the Sequence protocol, i.e. the types of the operands
are
Array<Array<Element>.Element>
which – as shown above – is just [Element]. But then the interface
is emitted using the bracket notation
[[Element].Element]
which should be the same, but is not accepted by the compiler.

Related

Swift Generic Type Equatable by sorting array

I'm trying to conform my generic CustomSet to Equatable but I get the following error when I try to sort the list array in the Equatable func:
Ambiguous reference to member '<'
I think the problem is that the compiler has no information on value types when comparing on sort, but I'm not sure how to tell it what it needs. Is this even possible to do on generic types?
The goal is to say CustomSet is Equal if list contains the exact same values.
struct CustomSet<T : Equatable> {
var list: [T]
init(_ list: [T]){
self.list = list
}
}
extension CustomSet : Equatable {
static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
return lhs.list.count == rhs.list.count && lhs.list.sorted(by: <) == rhs.list.sorted(by: <)
}
}
You need to restrict your generic type parameter to Comparable to be able to use the < operator on elements of list and hence sort list.
struct CustomSet<T : Comparable> {
var list: [T]
init(_ list: [T]){
self.list = list
}
}

What is "Element" type?

Reading Swift Programming Language book I've seen number of references to type Element, which is used to define type of collection items. However, I can't find any documentation on it, is it class, protocol? What kind of functionality/methods/properties it has?
struct Stack<Element>: Container {
// original Stack<Element> implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
...
If we tried trace the idea of how we do even get Element when working with collections, we would notice that it is related to the Iterator protocol. Let's make it more clear:
Swift Collection types (Array, Dictionary and Set) are all conforms to Collection protocol. Therefore, when it comes to the Collection protocol, we can see that the root of it is the Sequence protocol:
A type that provides sequential, iterated access to its elements.
Sequence has an Element and Iterator associated types, declared as:
associatedtype Element
associatedtype Iterator : IteratorProtocol where Iterator.Element == Element
You could review it on the Sequence source code.
As shown, Iterator also has an Element associated type, which is compared with the sequence Element, well what does that means?
IteratorProtocol is the one which does the actual work:
The IteratorProtocol protocol is tightly linked with the Sequence
protocol. Sequences provide access to their elements by creating an
iterator, which keeps track of its iteration process and returns one
element at a time as it advances through the sequence.
So, Element would be the type of returned element to the sequence.
Coding:
To make it simple to be understandable, you could implement such a code for simulating the case:
protocol MyProtocol {
associatedtype MyElement
}
extension MyProtocol where MyElement == String {
func sayHello() {
print("Hello")
}
}
struct MyStruct: MyProtocol {
typealias MyElement = String
}
MyStruct().sayHello()
Note that -as shown above- implementing an extension to MyProtocol makes MyElement associated type to be sensible for the where-clause.
Therefore sayHello() method would be only available for MyProtocol types (MyStruct in our case) that assign String to MyElement, means that if MyStruct has been implemented as:
struct MyStruct: MyProtocol {
typealias MyElement = Int
}
you would be not able to:
MyStruct().sayHello()
You should see a compile-time error:
'MyStruct.MyElement' (aka 'Int') is not convertible to 'String'
The same logic when it comes to Swift collection types:
extension Array where Element == String {
func sayHello() {
print("Hello")
}
}
Here is the definition in the Apple documentation
Element defines a placeholder name for a type to be provided later.
This future type can be referred to as Element anywhere within the
structure’s definition.
Element is usually used as the generic type name for collections, as in
public struct Array<Element> { ... }
so it is what you construct your array from, and not something predefined by the language.
Element is a purpose-built (and defined) placeholder for structures. Unlike some of the answers/comments have suggested, Element cannot always be substituted for T because T without the proper context is undefined. For example, the following would not compile:
infix operator ++
extension Array {
static func ++ (left: Array<T>, right: T) -> Array {
...
}
}
The compiler doesn't know what T is, it's just an arbitrary letter—it could be any letter, or even symbol (T has just become Swift convention). However, this will compile:
infix operator ++
extension Array {
static func ++ (left: Array<Element>, right: Element) -> Array {
...
}
}
And it compiles because the compiler knows what Element is, a defined placeholder, not a type that was arbitrarily made up.

Optional`s Equatable in Swift

We can compare two Optional variables through
public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool
But when i compare a String? and a String, it goes into the same function above. Why not:
public func ==<T : Equatable>(lhs: T?, rhs: T) -> Bool
In general, a function with arguments of some optional Type (Type?) does not imply the necessity of a variable of optional type as an input. In other words, take some function foo such that
func foo(in: Type?) { ... }
What this really means is that the function accepts both nil and Type variables as inputs (when unwrapped). Logically this is nil || Type, so of course a variable of class Type? can be taken as an input because it is identically nil or Type when unwrapped. However, even further, Type (non-optional) works just fine too because it satisfies one of the conditions in the logical expression.

Self in protocol

I am learning swift and playing with Xcode.
and I always dig into the definitions. I have seen that:
public protocol GeneratorType {
typealias Element
#warn_unused_result
public mutating func next() -> Self.Element?
}
A struct that conforming this protocol:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
I know 'Self' means that returning the conforming type. But what does 'Self.Element' mean?
and the function that implemented the requirement that returning 'Elements._Element?', I can’t see 'Elements._Element?' is equal to 'Self.Element?'.
Can anyone explain to me this?
and tell me more about this. thank you.
Self.Element refers to the concrete type that any type implementing GeneratorType protocol will declare as its Element typealias.
For example, in this generator of Fibonacci numbers:
struct Fibonacci: GeneratorType {
typealias Element = Int
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Element? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... you implement GeneratorType protocol and indicate what will be its Element typealias (Int in this case), and that's the type that generator's next() will be returning (well, actually the optional of that type).
Quite often, though, you would not have to explicitly specify typealiases when implementing parametrised protocols, as Swift is smart enough to infer them for you. E.g. for the Fibonacci numbers generator from the above example the following will also do:
struct Fibonacci: GeneratorType {
private var value: Int = 1
private var previous: Int = 0
mutating func next() -> Int? {
let newValue = value + previous
previous = value
value = newValue
return previous
}
}
... Swift knows from the signature of next() that it returns Int?, and that GeneratorType implementors also must have next() in their to-do list, and that these methods must return Element? types. So, Swift just puts 2 and 2 together, and infers that Element? must be the same thing as Int?, and therefore Element == Int.
About this:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public init(_ elements: Elements)
public mutating func next() -> Elements._Element?
}
Here we have four things going on:
We declare generic type IndexingGenerator that takes a parameter-type called Elements.
This Elements type has a constraint that it must implement Indexable protocol.
The generator that we implement is supposed to return values of the type that is accessible via Indexable interface of Elements, which is known to IndexingGenerator via dot-syntax as Elements._Element.
Swift infers that Element of IndexingGenerator is the same thing as Elements._Element.
So, essentially the above delclaration is equivalent to:
public struct IndexingGenerator<Elements : Indexable> : GeneratorType, SequenceType {
public typealias Element = Elements._Element
public init(_ elements: Elements)
public mutating func next() -> Element?
}
Finally, if curious why _Element and not just Element like in GeneratorType, here is what they write in the open-source Swift repository (under swift/stdlib/public/core/Collection.swift):
The declaration of _Element and subscript here is a trick used to break a cyclic conformance/deduction that Swift can't handle. We need something other than a CollectionType.Generator.Element that can be used as IndexingGenerator<T>'s Element. Here we arrange for the CollectionType itself to have an Element type that's deducible from its subscript. Ideally we'd like to constrain this Element to be the same as CollectionType.Generator.Element, but we have no way of expressing it today.

Comparing dictionaries containing actually equatable types, based on non-equatable data structures

So I want to equate two dictionaries of the same type [AnyLanguage: SortedList<String>].
AnyLanguage conforms to Hashable, and therefore also Equatable, so it's not a problem. SortedList on the other hand does not conform to Equatable, as it is generic over Element, which has no restrictions:
public struct SortedList<Element> { ... }
Now, I have implemented the equality operator for SortedList, when its Elements conform to Equatable:
public func ==<T: Equatable>(left: SortedList<T>, right: SortedList<T>) -> Bool
Now, when comparing two of the aforementioned dictionaries:
let dictA: [AnyLanguage: SortedList<String>] = [:]
let dictB: [AnyLanguage: SortedList<String>] = [:]
dictA == dictB
I get the following error:
I assume that the compiler is complaining because SortedList does not conform to Equatable, even though I have implemented the comparison operator for equatable Elements (which SortedList<String> would be able to use, as String is equatable).
How can I compare the two dictionaries?
The == operator for dictionaries requires that both Key and Value
type conform to Equatable.
You have implemented a (restricted) == operator for SortedList<Element>.
But implementing a == operator for a type does not make that type
Equatable automatically. The conformance must be declared explicitly.
Unfortunately, it is (currently) not possible to make SortedList<Element> conform to Equatable only if Element
is Equatable. The same problem exists for arrays, compare
Why can't I make Array conform to Equatable? for a discussion
in the Apple developer forum.
The only solutions – as far as I know – are to make SortedList<Element>
conform to Equatable unconditionally (as in Cristik's answer), or to define
a custom comparison operator for dictionaries
func ==<Key : Equatable, T : Equatable>(lhs: [Key : SortedList<T>], rhs: [Key : SortedList<T>]) -> Bool {
// ...
}
SortedList is not Equatable, so Dictionary can't compare the elements. You need to declare as Equatable, and implement == without the generic constraint. This will work:
public struct SortedList<Element>: Equatable { ... }
public func ==<T>(left: SortedList<T>, right: SortedList<T>) -> Bool
If you want to restrict your SortedList to Equatable elements, you can declare it to accept only stuff that conforms to Equatable
public struct SortedList<Element: Equatable>: Equatable
however for your SortedList I think Comparable would suit better.