Generic .to(<Type>) function?

Consider the following piece of code:

enum class TransactionType {
    CREDIT,
    DEBIT
}

fun String.toTransactionType() = TransactionType.valueOf(this)

What if I have a number of enum(s) like the above one and instead of crafting a String.toXYZ() extension function for each of them, I’d like to generalise the above function so that it works for any Enum, something like this:

inline fun <reified T : Enum<T>> String.to(typ: T): T = ...

How do I do that in Kotlin?


inline fun <reified T> String.convert(): T{
  return when(T::class){
    Double::class -> toDouble()
    Int::class -> toInt()
    ...
    else -> error("Converter unavailable for ${T::class}")
  } as T
} 

val i :Int = str.convert()

I do not recommend use of to since it clashes with the pair creation.

Thanks!

But this solution is not ‘maintenance free’ - every time I add a new target Type I need to add a new clause to the when handling that particular Type.
Does Kotlin (as it is now) provide means for a maintenance free (i.e. write-and-forget) solution?

How would Kotlin know how to create an appropriate object of that type?

1 Like

You need to provide the conversion method somehow. It you only want extensions with the same name, it could be done as well. Unlike Java, Kotlin allows dispatch on result type:

@JvmName("convertToInt")
fun String.convert(): Int = toInt()

val i: Int = str.convert()

@JvmName annotation is needed to avoid platform declaration clash.

It is not about creating an appropriate object;
It is about invoking the appropriate .valueOf(string) function.
With an inline <reified T ... perhaps it is (theoretically) doable.

Not all types have a valueOf(String) function. If you just want to support types that have one, you could do it (unsafely) with reflection, but that wouldn’t be a good idea.

EDIT:
Reflection is completely unnecessary in this particular case, enumValueOf<T>() exists:

inline fun <reified T : Enum<T>> String.enumOf(): T = enumValueOf(this)

Can be used like this:

enum class TransactionType {
    CREDIT,
    DEBIT
}

fun main() {
    val transaction: TransactionType = "CREDIT".enumOf()
}
4 Likes