Reputation: 53112
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
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