Consider this class with two functions, one with Int argument, the other with a generic one:
class C<K, V> {
// ...
operator fun f(index: Int): Pair<K, V> = ...
operator fun f(key: K): V = ...
}
When it is parameterized as C<Int, SomeType>, K is Int, and both functions match the calls, resulting into an error:
val m = C<Int, SomeType>()
m.f(1)
Overload resolution ambiguity. All these functions match:
public final fun f(index: Int): SomeTypedefined inCpublic final fun f(key: Int): Pair<Int, SomeType>?defined inC
How do I call whichever f I want in this case?
If you are lucky enough to have different parameter names of the functions, using named arguments will do the trick:
m.f(index = 1) // calls f(index: Int)
m.f(key = 1) // calls f(key: K)
Otherwise, if the parameter names are the same (or defined in Java), one possible workaround is to perform unchecked casts to make the compiler choose the desired option:
To call f(index: Int), you can use
@Suppress("UNCHECKED_CAST")
val s = (m as C<*, SomeType>).f(1) as Pair<Int, SomeType>
The cast to C<*, SomeType> makes K equivalent to in Nothing, out Any, meaning that there's no valid argument for f(key: K), so the call is naturally resolved to f(index: Int), but you need to cast the result back, because otherwise it is Pair<Any, SomeType>.
To call f(key: K), use:
@Suppress("UNCHECKED_CAST")
val s = (m as C<Any, SomeType>).f(1 as Any)
Similarly, the cast to C<Any, SomeType> changes the signature of the desired function to f(key: Any), and to call it, just upcast 1 to Any.
It's all the same in case of several type parameters clashing (e.g. f(key: K) and f(value: V) when K and V are both SomeType), just use named arguments or cast the object to ban one of the functions (in Nothing) or to make it accept Any.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With