Generic Where Clause Ambiguity with Associated Types in Swift - swift

I was writing some example code in a playground and wanted a function that returns the distance between two values, both of which conform to the Strideable protocol in Swift so that I could use the distance(to other: Self) -> Self.Stride function. My implementation was as follows:
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U
{
return a.distance(to: b)
}
After observing this function for a while, I realized that I wasn't sure which Stride was being used in the where clause, the one from a or from b. From what I understand it would be possible for a and b to define different associated types for Stride. Also I haven't made any statements to ensure that a.Stride == b.Stride, although I understand that I could expand my where clause to do so.
So, which one would get used to check equivalence to U? To be clear, the question isn't about this particular code block, but rather any situation in which this ambiguity would exist.

a and b are the same type. If you wanted them to be different Strideable types you would add another generic parameter conforming to Strideable such that the function signature appears as follows:
func bar<T: Strideable, V: Strideable, U>(_ a: T, to b: V) -> U where T.Stride == U, V.Stride == U {
return a.distance(to: a) //Trivial return statement (see explanation below)
}
Although the aforementioned code would compile, return a.distance(to: b) would not compile because they (a and b) are different types and the definition of distance in Swift3 is public func distance(to other: Self) -> Self.Stride (note the use of Self which restricts other to the same type as the Strideable upon which this function is called). In conclusion, although you could make a and b different types, for your application it would not make sense to do so.
As further evidence for not being able to call your original posted code with different types please see the attached
Playground screenshot which shows an error when using different types.
However, this works fine in the playground.
func distanceFrom<T: Strideable, U>(_ a: T, to b: T) -> U where T.Stride == U {
return a.distance(to: b)
}
let doubleFoo: Double = 4.5
let intFoo: Double = 4
let g = distanceFrom(doubleFoo, to: intFoo) // gives me a double of -0.5
I hope this helps.

Related

Swift Opaque Type vs Protocols - documentation infers protocol's func can't nest

On reading Apple's Swift Programming Language guide regarding opaque types, there's one paragraph I don't understand. The guide is discussing the differences between opaque types and protocols, and states that you can't nest calls that return a protocol type. They use this code fragment, where Shape is a protocol:
func protoFlip<T: Shape>(_ shape: T) -> Shape {
if shape is Square {
return shape
}
return FlippedShape(shape: shape)
}
It then states that:
Another problem with this approach is that the shape transformations don’t nest. The result of flipping a triangle is a value of type Shape, and the protoFlip(:) function takes an argument of some type that conforms to the Shape protocol. However, a value of a protocol type doesn’t conform to that protocol; the value returned by protoFlip(:) doesn’t conform to Shape. This means code like protoFlip(protoFlip(smallTriange)) that applies multiple transformations is invalid because the flipped shape isn’t a valid argument to protoFlip(_:).
However, I wrote this code:
import Foundation
protocol P {
associatedtype AT
}
struct C: P {
typealias AT = Int
}
func f<T: P>(_ t: T) -> T {
t
}
func g() {
f(f(C()))
}
g()
and this compiles and runs...and appears to let me nest those calls.
What am I mis-understanding? What is the documentation trying to say?
You wrote this:
func f<T: P>(_ t: T) -> T
This takes and returns the same type.
That's not the problem. The problem is the example:
func protoFlip<T: Shape>(_ shape: T) -> Shape
This takes a T and returns a Shape existential.
This would be equivalent to:
func f<T: P>(_ t: T) -> P
(Takes a T and returns a P existential.)
If you wrote that, you'd find you have the issue described. You cannot pass a P existential into f() because protocol existentials do not conform to their protocol in Swift. (This is due to various corner-cases it can create due to static methods and initializers. Rather than deal with the corner-cases, today protocol existentials just do not conform to their protocol. This may change in the future for the cases where it could be allowed but isn't currently.)
Opaque types allow you to write:
func f<T: P>(_ t: T) -> some P
Rather than returning a P existential, this returns a concrete (but opaque) type that conforms to P. The system tracks this as "the type that is returned by f when parameterized by T." It is not equivalent to any other some P, but it is concrete, it is known at compile time, and it can be passed into f().

Generic parameter 'T' could not be inferred after assignment

// Xcode 11.6 / Swift 5
import Foundation
func f<T>(_: (T) -> Void) { }
#discardableResult
func g(_: Int) -> Int { 0 }
f { g($0) } // compiles fine
f { let _ = g($0) } // Generic parameter 'T' could not be inferred
In the above code, the generic function f expects as its argument a function that takes an argument of type T.
The function g takes an argument of type Int.
When I write f { g($0) }, the code compiles. I believe (please correct me if I'm wrong) this compiles because the compiler can infer that T is an Int based on g's argument type.
However, when I try to do something with the return value of g, for example in the let _ = g($0) line, the compiler complains that it can no longer infer the type of T.
It seems to me the return type of g should have no bearing on how the compiler infers T's type, but clearly it does.
Can anyone shed some light on why this happens, and what (if anything) can be done to correct it?
This may or may not be a compiler bug.
It is known that Swift does not try to infer the types of some closures, namely, multi-statement ones, as said in SR-1570:
This is correct behavior: Swift does not infer parameter or return types from the bodies of multi-statement closures.
However, your closure consists of only one statement, one declaration to be specific. It is possible, albeit weird, that they designed it so that Swift doesn't try to infer types if the closure contains one declaration as well. For example, this does not compile either
f { let x: Int = $0 } // nothing to do with "g"! The issue seems to be with declarations
If this were by-design, the rationale behind it might be because a single declaration in a closure doesn't make much sense anyway. Whatever is declared, won't be used.
But again, this is just speculation, and this could be a bug as well.
To fix it, simply make it a not-a-declaration:
f { _ = g($0) } // this, without the "let", is IMO the idiomatic way to ignore the function result
Or
f { g($0) } // g has #discardableResult anyway, so you don't even need the wildcard
The function f takes in a function as a parameter which in turn takes a parameter of type T and returns nothing (Void). For a closure to infer types automatically, it has to consist of single (and sometimes simple) expression. Anything complex makes it difficult for the compiler to infer (which makes sense from the compiler's standpoint). Apparently, let _ = g($0) is a complex statement as far as the compiler is concerned. For further information, see this mailing list discussion
it looks like #discardableResult gives you an ability to have 2 types of functions:
g(_: Int) -> Int and g(_: Int) -> Void (it is when you don't want to use a result of function)
I think that
f { g($0) } - here your f can infer a type because it has the same Type
(_: (T) -> Void) and (_: (Int) -> Void)
f { let _ = g($0) } - in this case the type of g function is different from f function
(_: (T) -> Void) and (_: (Int) -> Int)
If you will remove "let" it will compile again:
f { _ = g($0) }
I think that
f { let _ = g($0) } - return only Int value
f { _ = g($0) } - return function (_: (Int) -> Int)
Maybe it is a key here

How to use Equatable protocol on two objects of an unknown type?

Say I have two variables, and I don't know what type they are (and it's not possible to know what type they are until runtime):
var a: Any
var b: Any
How can I test if they are equal, using the Equatable protocol? I can't just do a == b because that requires that both of the items are the same, Equatable type, and the compiler can't prove that because they could be different types (and one or both might not even be Equatable).
So, is it possible to tell the compiler to check if they both have the same type, and if that type conforms to Equatable, then to use the == operator on them and return the result, otherwise returning false?
If there is no way to do this, is there a good reason Swift prevents this, or is it a current limitation of Swift that could be fixed in the future?
Under the assumption that if a and b differ in type then they are never equal, you can use a generic function with constraint to achieve the goal.
func isEqual<T : Equatable>(a: T, b: T) -> Bool {
return a == b;
}
You cannot have a and b differ in type, as the Equatable protocol assumes that the LHS and RHS of the comparison are of the same type. This seems a reasonable constraint, but one can certainly write a notion of equality that doesn't require this. In these cases, you'll need your own equality protocol.
You use generics and function overload:
func isEqual<T: Equatable>(a: T, b: T) -> Bool {
return a == b
}
func isEqual<T, U>(a: T, b: U) -> Bool {
return false
}
If both variables have the same type, as that type conforms to Equatable, then the compiler will choose the first function, otherwise will go the second one.
This will work for Objective-C objects too, providing you cast to NSObject before calling the function: isEqual(var1 as? NSObject, var2 as? NSObject)

Which type of value can be compared in switch statement in Swift2

I wonder which type of value can be compared in switch statement. The official document said:
Cases can match many different patterns, including interval matches, tuples, and casts to a specific type
Is there anything else? Can I compare class type in switch statement?
Suppose I hava a class A:
class A {
}
func == (lhs: A, rhs: A) -> Bool { return true }
Then I can check if two objects of class A are equal. But I still can't do like this:
var a1 = A(); var a2 = A()
switch a1 {
case a2: //do something
}
Although we rarely write codes like these, I'm still very curious about how switch statement works in Swift.
As explained in Expression Patterns,
The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ~= operator.
You can define func ~=(lhs: A, rhs: A) if you wish for your custom type to be used in a switch statement.
But I'd also recommend simply using the Equatable protocol, implementing ==, and then you can write if a1 == a2 { ... }.
In fact, the standard library provides
public func ~=<T : Equatable>(a: T, b: T) -> Bool
So if you conform to Equatable, you don't need to provide your own ~=.

Swift higher order function (Church pair aka cons) with generic parameter types not accepting input parameter types

I was messing around with the functional programming in Swift 2.1, trying to implement the Church encoding pair/cons function (cons = λx λy λf f x y in untyped lambda calculus), which I had read couldn't be done in earlier versions of Swift.
With generics it looks like
func cons<S,T,U>(x:S,_ y:T) -> ((S,T) -> U) -> U
{
return { (f:((S,T) -> U)) -> U in return f(x,y)}
}
cons(1,2)
//error: cannot invoke 'cons' with an argument list of type '(Int, Int)'
//note: expected an argument list of type '(S, T)'
which doesn't work, and gives an error I cannot understand (surely parameter list of type (Int,Int) can match generic type variables (S,T)?)
If you get rid of the generic types, and declare them all Ints, the function works, but of course we want to be able to cons together lists longer than 2; consing a list of length 3 is consing an Int with an (Int,Int) -> Int, for example.
Another option is to type everything as Any (see Type Casting for Any and AnyObject), but I couldn't make that work either.
Do you have any ideas? Is this possible in Swift yet? I'm sure there are simpler ways to implement cons/car/cdr, but I'm specifically interested in the Church encoding, where the list elements are arguments to anonymous functions (lambdas).
func cons<S,T,U>(x:S,_ y:T) -> ((S,T) -> U) -> U
{
return { (f:((S,T) -> U)) -> U in return f(x,y)}
}
let i: ((Int,Int)->Int)->Int = cons(1,2)
let d: ((Int,Int)->Double)->Double = cons(2,3)
let e: ((Double,Int)->String)->String = cons(2.2, 1)
let e: ((Double,Int)->Double)->Double = cons(2.2, 1)
stil one of type is an 'extra' type and could not be inferred by compilator. if you define the types, you can see, that not all combinations are valid. Just define the output type and the compilator should be happy
func cons<S,T, U>(x:S,_ y:T, outptAs: U.Type) -> ((S,T) -> U ) -> U
{
return { (f:((S,T) -> U)) -> U in return f(x,y) }
}
let i = cons(1.2 ,"A", outptAs: Int.self)
let j = cons("alfa","beta", outptAs: Double.self)