Logan
Logan

Reputation: 53112

Why doesn't swift infer the appropriate overload function with a generic return argument without a type constraint?

Note

Swift is changing rapidly, this question was asked regarding:

Xcode 7, Swift 2.0

Explanation

I'm looking to implement a generic return argument. Quite often, I find it necessary to implement an optional version overload so I can access the underlying type and handle it appropriately. Here's some manufactured functions. The assignment of String is just there as a placeholder for replication:

func ambiguous<T>() -> T {
    let thing = "asdf"
    return thing as! T
}

func ambiguous<T>() -> T? {
    return nil
}

Now, if we look at the implementation:

// Fine
let a: String = ambiguous()

// Ambiguous
let b: String? = ambiguous()

This might seem obvious because you could assign type T to a variable of type T?. So it makes sense that it would have trouble inferring. The problem is, that with a type constraint, it suddenly works. (This can be anything, I'm using Equatable for easy replication.

func nonAmbiguous<T : Equatable>() -> T {
    let thing: AnyObject = "asdf"
    return thing as! T
}

func nonAmbiguous<T : Equatable>() -> T? {
    return nil
}

And now, it functions as expected:

// Fine
let c: String = nonAmbiguous()

// Fine
let d: String? = nonAmbiguous()

Note, this also works with other type:

func nonAmbiguous<T>() -> [T] {
    let thing: AnyObject = ["asdf"]
    return thing as! [T]
}

func nonAmbiguous<T>() -> [T]? {
    return nil
}

// Fine
let e: [String] = nonAmbiguous()

// Fine
let d: [String]? = nonAmbiguous()

Question:

Is there a way to have a return generic argument infer the appropriate overload through optionality?

if no

Is this a language feature, or a bug somewhere. If it's a language feature, please explain the underlying issue preventing the possibility of this behavior.

Upvotes: 2

Views: 209

Answers (1)

Martin R
Martin R

Reputation: 539745

The first example is ambiguous because T can be inferred as both String and String?.

The second example is not ambiguous because String is Equatable but String? is not, so T : Equatable cannot be inferred as String?.

The third case is not ambiguous because [T] is not inferred as [String]?.

Remark: Generally, Optional<Wrapped> does not conform to Equatable even if Wrapped does, in the same way as Array<Element> does not conform to Equatable even if Element does. This is a restriction of the current type system in Swift which might be improved in a future version, compare

from the Swift development mailing list.

Upvotes: 2

Related Questions