Home > Software design >  Generic infix function with several upper bounds
Generic infix function with several upper bounds

Time:10-14

I am trying to do this

infix fun Int.divBy (_denom: Int): Rational {
    var num = this.toBigInteger()
    var denom = _denom.toBigInteger()

    // reduce result
    val result = Rational(num, denom)
    result.reduce()

    // return
    println("Returning: Rational $result")
    return result
}

but for Long, Int and BigInteger, and without having to rewrite the same for all of them. I tried this, but I get an error:

infix fun <T> T.divBy (_denom: T): Rational where
    T: Int, T:BigInteger, T: Long
    {
     ....
}
 

So that things like val third = 1 divBy 3 can be done.

Error 1

CodePudding user response:

I believe this is not possible, because there is no interface for "something convertable to BigInteger". Still, you can keep most of your code in a single function receiving BigInteger objects and provide multiple functions for just converting to BigInteger:

infix fun Int.divBy(denom: Int): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun Long.divBy(denom: Long): Rational = toBigInteger() divBy denom.toBigInteger()

inline infix fun BigInteger.divBy (denom: BigInteger): Rational {
    // reduce result
    val result = Rational(this, denom)
    result.reduce()

    // return
    println("Returning: Rational $result")
    return result
}

Edit (@ademord): the final solution looks like this, after cleaning it up:

infix fun Int.divBy(denom: Int): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun Long.divBy(denom: Long): Rational = toBigInteger() divBy denom.toBigInteger()
infix fun BigInteger.divBy (denom: BigInteger): Rational = Rational(this, denom).reduce()

As a side note, it can't be done with generics and upper bounds, because their main purpose is that the code inside the function knows what is the type of T. where clause is used to specify multiple requirements that T needs to satisfy altogether. Upper bounds are ANDed, not ORed. Note that if they would be ORed then we would still have to add runtime type checks and casts, which is exactly what we try to avoid providing upper bounds (thanks @Tenfour04 for pointing this out).

  • Related