I wanted to implement min()
/max()
aliases for the Kotlin's Comparable<T>coerceAtLeast()
/coerceAtMost()
, if nothing else for the exercise of extending an Interface (I've only extended classes so far).
I tried this:
fun <T>Comparable<T>.max(other:T) : T {
return this.coerceAtLeast(other)
}
But I get the following error:
Type inference failed: Cannot infer type parameter T in fun <T : Comparable<T#1 (type parameter of kotlin.ranges.coerceAtLeast)>> T#1.coerceAtLeast(minimumValue: T#1): T#1
None of the following substitutions
receiver: Any? arguments: (Any?)
receiver: Comparable<T#2 (type parameter of com.nelsonirrigation.twig.plans.extensions.max)> arguments: (Comparable<T#2>)
receiver: T#2 arguments: (T#2)
receiver: Comparable<Comparable<T#2>> arguments: (Comparable<Comparable<T#2>>)
can be applied to
receiver: Comparable<T#2> arguments: (T#2)
At which point my limited understanding of Kotlin generics basically overflowed. Is what I'm trying to do achievable? What is the piece of the puzzle I'm missing?
You'll notice in the implementation of coerceAtLeast
that the declaration of the extension function is a little different from what you have:
fun <T : Comparable<T>> T.coerceAtLeast(minimumValue: T): T
If you change your declaration to match, it compiles.
This comes down to the problem of the type of minimumValue
. In your version, it's not enforced that minimumValue
's type implements Comparable<T>
, so it can't coerce your other
to a type that complies with the contract of coerceAtLeast
.
Note that it is possible to write an extension function on an interface directly, it's a consequence of calling another method that doesn't match your typing configuration that causes this to break.