Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with an overload resolution ambiguity of functions with generics?

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): SomeType defined in C
  • public final fun f(key: Int): Pair<Int, SomeType>? defined in C

How do I call whichever f I want in this case?

like image 452
hotkey Avatar asked Nov 21 '16 14:11

hotkey


1 Answers

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.

like image 97
hotkey Avatar answered Sep 28 '22 00:09

hotkey