How to use Swift opaque types in combination with literals?

118 Views Asked by At

I have the following function

func greater<T: Comparable>(_ lhs: T, rhs: T) -> some Comparable {
    lhs > rhs ? lhs : rhs
}

But when I try the following I get an error

greater(greater(1, 2), 3) // Cannot convert value of type 'Int' to expected argument type 'some Comparable'

I understand the error but why is not the compiler able to infer that both types are actually Ints?

2

There are 2 best solutions below

0
On

When could that function possibly return another type than what was the input type so redeclare it as

func greater<T: Comparable>(_ lhs: T,_ rhs: T) -> T {
    lhs > rhs ? lhs : rhs
}

or another way to look at it, when returning some Comparable we could change the function to below and it would still be valid

func greater<T: Comparable>(_ lhs: T,_ rhs: T) -> some Comparable {
    lhs > rhs ? "First argument" : "Second Argument"
}
0
On

You shouldn't use an opaque return type for your needs. A simple generic return type should suffice.

The problem with an opaque return type in your example is that it masks the actual type information and hence the type of greater(1, 2) will not be the same as the type of 3 - some Comparable and Int are not the same, even if that some Comparable is actually an Int.

Moreover, you want to return the exact same type as your input arguments, which is T, not some Comparable. If your return type was some Comparable, you could easily return any other Comparable types from your function instead of returning the input type.

The correct implementation is:

func greater<T: Comparable>(_ lhs: T, rhs: T) -> T {
    lhs > rhs ? lhs : rhs
}