0

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?

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167

1 Answers1

2

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.

emerssso
  • 2,376
  • 18
  • 24