How to call ambiguous generic function in Swift?
This is ambiguous because Int
is both Hashable
and Comparable
, and neither of those two protocols are in the same hierarchy. (You can view the Int
protocol hierarchy on Swifter.)
func f<T: Hashable>(t: T) {
println("Hashable: \(t)")
}
func f<T: Comparable>(t: T) {
println("Comparable: \(t)")
}
let number = 5
f(number)
// error: ambiguous use of 'f'
You can't explicitly tell it which function to call, because of the associated type requirements of each protocol, but what you can do is define a third function:
func f<T: Comparable where T: Hashable>(t: T) {
println("Both Hashable & Comparable: \(t)")
}
f(number)
// Both Hashable & Comparable: 5
This is how Swift implements the ..<
operator, which otherwise would be ambiguous for types that implement both Comparable
and ForwardIndexType
.
To expand a little further, here's a look at what I meant by "you can't explicitly tell it which function to call, because of the associated type requirements of each protocol." Protocols can be used as types, as described in the Swift book chapter on Protocols:
protocol RandomNumberGenerator {
func random() -> Double
}
class Dice {
let generator: RandomNumberGenerator
// ...
}
In this example, the generator property can be any type that conforms to RandomNumberGenerator
- similar to how id<ProtocolName>
is used in Objective-C. However, protocols can only be used as types when they do not include an associated type or reference Self
in their declaration. This unfortunately excludes nearly every built-in type in Swift, including Hashable
and Comparable
.
Hashable
inherits from Equatable
, which references Self
when defining the ==
operator:
func ==(lhs: Self, rhs: Self) -> Bool
and Comparable
does the same with its operators:
func <=(lhs: Self, rhs: Self) -> Bool
// similar definitions for <, >, and >=
These protocols can only be used as generic constraints, and not used as a type when declaring a variable. (As far as I can tell this is undocumented, but discoverable through error messages.)
Two protocols that don't have that restriction are Printable
and BooleanType
, so we can look at how they work. Bool
is the only built-in type that conforms to BooleanType
, and it is also Printable
, so that will be our test type. Here are our generic functions p()
and the variable t
- note that, as before, we can't just call the function with t
:
func p<T: Printable>(t: T) {
println("Printable: \(t)")
}
func p<T: BooleanType>(t: T) {
println("BooleanType: \(t)")
}
let t: Bool = true
p(t)
// error: Ambiguous use of 'p'
Instead, we need to cast (upcast?) t
to a particular protocol using the as
keyword, and call a particular generic function that way:
p(t as Printable)
// Printable: true
p(t as BooleanType)
// BooleanType: true
So as long as we have a qualifying protocol, we can choose which variant of the generic method to call.
Swift 4: Ambiguous Expression in reduce and generics
Got it to work by telling the compiler that the sequence elements (which is what ends up in the Zip2Sequence
) also conform to Equatable
:
func allItemsMatch<C1, C2>(_ s: C1, _ t: C2) -> Bool
where C1: Container, C2: Container,
C1.Item: Equatable, C1.Element: Equatable,
C1.Element == C2.Element, C1.Item == C2.Item,
C1: Sequence, C2: Sequence {
if s.count != t.count {
return false
}
return zip(s, t).reduce(true) { eq, tuple in
eq && (tuple.0 == tuple.1)
}
}
Related Topics
Access Class Property from Instance
Table View's 'Cellforrow(At:)' Is 'Nil' in Unit Test
How to Define a Variable in a Swift If Statement
Type 'Bundle' Has No Member "Module"
Cell Is Duplicated Multiple Times When Posting to Firebase
Window Title Bar Appears Transparent Issue (Not Really Transparent)
Hide Header While Collection View Is Loading
Swift & Firebase: Detect Revoked Token
How to Unwrap Optional<Optional<T>> in Swift 1.2
When How to Start Submitting Apps to The iOS App Store Written Using The Swift Programming Language
Convert Time String into Date Swift
Swift Increment Int! Not Working
How to Fix Cannot Find 'Firebaseapp' in Scope
Why Is Swift Counting This Grapheme Cluster as Two Characters Instead of One
How to Spin and Add a Linear Force to an Entity Loaded from Reality Composer