Optional`s Equatable in Swift - 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.

Related

What does the swift keyword Wrapped mean in the Optional extension?

What does the swift keyword Wrapped mean in the Optional extension?
extension Optional {
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
In extensions, the generic parameters of the type that you are extending can be referenced by just writing their simple names, and notice that Optional is a generic type.
#frozen enum Optional<Wrapped>
So Wrapped in the function declaration refers to the generic parameter declared there.
As you may know, optional types are usually written as T? (where T is some type), which is a syntactic sugar for Optional<T>. For example, Int? is the same as Optional<Int>, and String? is the same as Optional<String>, etc.
In other words, Wrapped basically just means the type that precedes the ?, whatever that may be. If you have a String? (aka Optional<String>), then the signature of flatMap for that would be:
func flatMap<U>(_ transform: (String) -> U?) -> U?
There is no keyword "Wrapped." This is a type parameter. This is similar to runtime parameters. If you see:
func f(x: Int) { ... }
x is not a keyword. It's just a parameter name. In the same way, Optional is defined as:
enum Optional<Wrapped>
"Wrapped" is just the type parameter passed to Optional. So in this extension:
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
"Wrapped" just refers to whatever Optional is wrapping.

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

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.

Overriding / operator for Optionals using generics results in endless loop

lets take a look at the following code snippet:
func / <T>(lhs: T?,rhs: T?) throws -> T? {
switch (lhs,rhs) {
case let (l?,r?):
return try l/r
default:
return nil
}
}
let x : Double? = 2
let y : Double? = 2
let z = try! x/y
I created a generic function that expects two optional parameters. If I run this code it leads to an endless loop because try l/r uses func / <T>(lhs: T?,rhs: T?) to divide the values. Can anyone explain why dividing two none optional double values results in a function call to the method I wrote and not the default / operator definition for Double?
If I extend Double by an extension that requires a static / operator for that class everything works like a charm:
protocol Dividable {
static func /(lhs: Self, rhs: Self) -> Self
}
extension Double: Dividable {}
func / <T:Dividable>(lhs: T?,rhs: T?) throws -> T? {
switch (lhs,rhs) {
case let (l?,r?):
return l/r
default:
return nil
}
}
let x : Double? = 2
let y : Double? = 2
let z = try! x/y
The binary arithmetic for e.g. Double is not implemented using concrete Double types, but rather as default generic implementations for types conforming to FloatingPoint:
swift/stdlib/public/core/FloatingPoint.swift.gyb
Within the block of your custom / function, the compiler does not know that the typeholder T conforms to FloatingPoint, and the overload resolution of l/r will resolve to the method itself (since the FloatingPoint implementions, while being more specific, are not accessible to the more general non-constrained type T in your custom implementation).
You could workaround this by adding FloatingPoint as a type constraint also to your own custom method:
func /<T: FloatingPoint>(lhs: T?, rhs: T?) throws -> T? {
switch (lhs, rhs) {
case let (l?, r?):
return try l/r
default:
return nil
}
}
Likewise, the binary arithmetic for integer types are implemented as default generic implementations constrained to types conforming to the internal protocol _IntegerArithmetic, to which the public protocol IntegerArithmetic conforms.
swift/stdlib/public/core/IntegerArithmetic.swift.gyb
You can use the latter public protocol to implement an overload of your custom operator function for integer types.
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) throws -> T? {
switch (lhs, rhs) {
case let (l?, r?):
return try l/r
default:
return nil
}
}
Finally, you might want to consider why you'd want this function to throw. N also ote that there are ways to simplify you implementations when dealing with exactly two optional values that you want to operate on only in case both differ from nil. E.g.:
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { l in rhs.map{ l / $0 } }
}
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) -> T? {
return lhs.flatMap { l in rhs.map{ l / $0 } }
}
Of, if you prefer semantics over brevity, wrap your switch statement in a single if statement
func /<T: FloatingPoint>(lhs: T?, rhs: T?) -> T? {
if case let (l?, r?) = (lhs, rhs) {
return l/r
}
return nil
}
func /<T: IntegerArithmetic>(lhs: T?, rhs: T?) -> T? {
if case let (l?, r?) = (lhs, rhs) {
return l/r
}
return nil
}
Your function signature doesn't let the compiler know anything about the type of lhs and rhs, other than that they're the same type. For example you could call your method like this:
let str1 = "Left string"
let str2 = "Right string"
let result = try? str1 / str2
This will result in an infinite loop because the only method that the compiler knows called / that takes in 2 parameters of the same type (in this case String) is the one that you've declared; return try l/r will call your func / <T>(lhs: T?,rhs: T?) throws -> T? method over and over again.
As you mentioned in your question, you will need a protocol that your parameters must conform to. Unfortunately there is no existing Number or Dividable protocol that would fit your needs, so you'll have to make your own.
Note that division will crash when the denominator is 0 and will not throw an error, so you should be able to remove the throws keyword from your function so that it is:
func / <T:Dividable>(lhs: T?, rhs: T?) -> T?
Edit to clarify further
If you think about what the compiler knows at that point I think it makes more sense. Once inside the function all the compiler knows is that lhs and rhs are of type T and optional. It doesn't know what T is, or any of its properties or functions, but only that they're both of type T. Once you unwrap the values you still only know that both are of type T and non-optional. Even though you know that T (in this instance) is a Double, it could be a String (as per my example above). This would require the compiler to iterate over every possible class and struct to find something that supports your method signature (in this case func / (lhs: Double, rhs: Double) -> Double), which it simply can't do (in a reasonable time), and would lead to unpredictable code. Imagine if you added this global method and then every time / was used on something existing (such as Float(10) / Float(5)) your method was called, that would get pretty messy and confusing pretty quickly.

What is the syntax for a closure argument in swift

In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question

Swift Optional type: how .None == nil works

I'm trying to understand how does it work:
1> func returnNone() -> String? { return .None }
2> returnNone() == nil
$R0: Bool = true
3> returnNone() == .None
$R1: Bool = true
Why .None is equal nil.
I don't see anything about it in enum definition:
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
/// Construct a `nil` instance.
public init()
/// Construct a non-`nil` instance that stores `some`.
public init(_ some: Wrapped)
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
#warn_unused_result
#rethrows public func map<U>(#noescape f: (Wrapped) throws -> U) rethrows -> U?
/// Returns `nil` if `self` is nil, `f(self!)` otherwise.
#warn_unused_result
#rethrows public func flatMap<U>(#noescape f: (Wrapped) throws -> U?) rethrows -> U?
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}
enum Optional conforms to the NilLiteralConvertible protocol,
which means that it can be initialized with the "nil" literal.
The result is Optional<T>.None where the type placeholder T
must be inferred from the context.
As an example,
let n = nil // type of expression is ambiguous without more context
does not compile, but
let n : Int? = nil
does, and the result is Optional<Int>.None.
Now optionals can in general not be compared if the underlying
type is not Equatable:
struct ABC { }
let a1 : ABC? = ABC()
let a2 : ABC? = ABC()
if a1 == a2 { } // binary operator '==' cannot be applied to two 'ABC?' operands
and even this does not compile:
if a1 == Optional<ABC>.None { } // binary operator '==' cannot be applied to two 'ABC?' operands
But this compiles:
if a1 == nil { }
It uses the operator
public func ==<T>(lhs: T?, rhs: _OptionalNilComparisonType) -> Bool
where _OptionalNilComparisonType is not documented officially.
In https://github.com/andelf/Defines-Swift/blob/master/Swift.swift the
definition can be found as (found by #rintaro and #Arsen, see comments):
struct _OptionalNilComparisonType : NilLiteralConvertible {
init(nilLiteral: ())
}
This allows the comparison of any optional type with "nil", regardless of whether the underlying type is Equatable or not.
In short – in the context of Optional – nil can be thought of as a shortcut to .None, but the concrete type must be inferred from the context. There is a dedicated == operator for comparison with "nil".