0

Try to write a simple Kotlin infix function for plus operation. What's wrong with generic type?

infix fun <T : Number> T.myPlus(that: T): T = this + that
6
  • Thx for quick reply ;) Yeah, right. How can I restrict a type for simple arithmetic operations? Extending Number seemed right design. I don't want to write a plus extension for Number. Commented May 28, 2022 at 14:44
  • Just for testing infix and generics. Commented May 28, 2022 at 14:48
  • Something like this: infix fun <T> T.infixPlus(that: T) : T where T : Int, T : Double, T : Float = (this + that) as T Commented May 28, 2022 at 14:50
  • 1
    It has nothing to do with generics. You just cannot add a Number to another Number. There is no plus method defined in the abstract class Number, see kotlinlang.org/api/latest/jvm/stdlib/kotlin/-number. Commented May 28, 2022 at 14:57
  • So the best way in this stupid example is to write to separate methods for each type? // infix fun Int.infixPlus(that: Int) : Int = this + that // infix fun Float.infixPlus(that: Float) : Float = this + that // infix fun Double.infixPlus(that: Double) : Double = this + that Commented May 28, 2022 at 15:00

4 Answers 4

1

As others have mentioned, there's no solutions using generics for various reasons. You have to define an extension function for each Number type (Byte, Short, Int, Long, Float, Double). E.g. for Int you could do:

when (that) {
    is Byte, is Short, is Int, is Long -> that.toLong().plus(this)
    is Float -> that + this
    is Double -> that + this
    else -> throw Exception("Types mismatch")
}

Even doing that, in some cases you need to decide whether you want to truncate or round the result.

val n1 = 1230000000000000000L
val n2 = 123.7

This case (n1 is a Long, n2 is a Float) could be handled like this:

is Float -> this + that.toLong()

resulting in 1230000000000000123

or it could be handled like this:

is Float -> this.toFloat() + that

resulting in 1.23E18

Sign up to request clarification or add additional context in comments.

Comments

0

You forgot the operator keyword:

infix operator fun T.plus(that: T): T = this + that

Edit:

infix fun Number.infixPlus(that: Number): Number =
  when (that) {
    is Int    -> this.toInt() + that
    is Long   -> this.toLong() + that
    is Float  -> this.toFloat() + that
    is Double -> this.toDouble() + that
    else      -> throw Exception()
  }

val n1 = 123
val n2 = 123.456

val result = n1 infixPlus n2

println("result: " + result)

println("is Int: " + (result is Int))
println("is Long: " + (result is Long))
println("is Float: " + (result is Float))
println("is Double: " + (result is Double))

4 Comments

Wouldn't this cause infinite recursion?
No, the main aim to create a custom new infix function without overloading plus operator.
You're both right. Amended my answer to reflect that.
Tnx for replies!
0

A bit more casting safety:

infix fun Number.infixPlus(that: Number): Number {
    return when {
        this is Int && that is Int -> this + that
        this is Double && that is Double -> this + that
        this is Float && that is Float -> this + that
        else -> throw Exception("Types mismatch")
    }
}

In prev. example args:

val n1 = 1230000000000000000L
val n2 = 123

val result = n1 infixPlus n2
result: -1313144709

No exception and wrong result.

1 Comment

Unfortunately it's runtime only checks.
0

You have to find the correct type of the result:

val types = listOf("Double", "Float", "Long", "Integer", "Short", "Byte")
infix fun <T : Number> T.myPlus(that: T): T {
    return when(types[min(types.indexOf(this.javaClass.simpleName), types.indexOf(that.javaClass.simpleName))]) {
        types[0] -> (this.toDouble() + that.toDouble()) as T
        types[1] -> (this.toFloat() + that.toFloat()) as T
        types[2] -> (this.toLong() + that.toLong()) as T
        types[3] -> (this.toInt() + that.toInt()) as T
        types[4] -> (this.toShort() + that.toShort()) as T
        types[5] -> (this.toByte() + that.toByte()) as T
        else -> throw IllegalArgumentException()
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.