Reputation: 13673
I'd like to write a generic Kotlin function that works with arbitrary types, as long as they support some basic numeric operations, such as comparison and addition. Something like this (note: this code doesn't compile):
fun <T : ???> twiceTheLarger(a: T, b: T) = if (a > b) a + a else b + b;
In C++, this kind of code works. The following C++ twiceTheLarger
function takes anything that supports the +
and >
operators, be it a primitive numeric type or a custom class:
#include <iostream>
template <typename T> T twiceTheLarger(T a, T b) {
return a > b ? a + a : b + b;
}
int main() {
std::cout << twiceTheLarger(1, 2) << std::endl; // int values
std::cout << twiceTheLarger(42.0, 1.0) << std::endl; // double values
}
How can I get a similar result in Kotlin? The best way I could come up so far is to explicitly pass an object with the required functions, like this:
interface NumericOperators<T> {
fun plus(a: T, b: T): T
fun greaterThan(a: T, b: T): Boolean
}
object IntNumericOperators : NumericOperators<Int> {
override fun plus(a: Int, b: Int) = a + b
override fun greaterThan(a: Int, b: Int) = a > b
}
object DoubleNumericOperators : NumericOperators<Double> {
override fun plus(a: Double, b: Double) = a + b
override fun greaterThan(a: Double, b: Double) = a > b
}
fun <T> twiceTheLarger(a: T, b: T, operators: NumericOperators<T>) =
if (operators.greaterThan(a, b)) operators.plus(a, a) else operators.plus(b, b)
fun main() {
println(twiceTheLarger(1, 2, IntNumericOperators)) // int values
println(twiceTheLarger(42.0, 1.0, DoubleNumericOperators)) // double values
}
Is there a better way?
Edit:
I realize that I could create overloads for each primitive numeric type. The thing is that I'm writing a library function that needs to work with arbitrary number-like types, even types my library doesn't know about. So type-specific overloads are not an option.
Upvotes: 4
Views: 495
Reputation: 50578
You will need to create functions for each primitive type. You can't use <T : Number>
, despite all numbers in Kotlin inherit this. Number
superclass is used only for the castings.
You'll need to create functions or extension functions:
fun Int.twiceTheLarger(a: Int, b: Int) = if (a > b) a + a else b + b;
fun Double.twiceTheLarger(a: Double, b: Double) = if (a > b) a + a else b + b;
It would be great if you can utilize Comparable<T>
in another function for the comparison. Types of T
need to overload operator fun plus(other: T)
as well.
interface Addable<T>: Comparable<T>{
operator fun <T> Addable<T>.plus(a: T)
}
fun <T : Addable<T>> T.twiceTheLarger(a: T, b: T) {
return if (a > b) a.plus(a) else b + b
}
Upvotes: 3